首页 > 代码库 > session生命周期
session生命周期
session生命周期2
(2011-05-05 13:46:22)标签: 杂谈 |
Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session"活跃(active)"了一次。
由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。
Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(long interval)修改。
Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法可以使Session失效。
Session中包括各种方法,使用起来要比Cookie方便得多。Session的常用方法如表5.2所示。
表5.2 HttpSession的常用方法
方 法 名
描 述
void setAttribute(String attribute, Object value) 设置Session属性。value参数可以为任何Java Object。通常为Java Bean。
value信息不宜过大
String getAttribute(String attribute) 返回Session属性
Enumeration getAttributeNames() 返回Session中存在的属性名
void removeAttribute(String attribute) 移除Session属性
String getId() 返回Session的ID。该ID由服务器自动创建,不会重复
long getCreationTime() 返回Session的创建日期。返回类型为long,常被转化为Date类型,例如:
Date createTime = new Date(session.getCreationTime())
long getLastAccessedTime() 返回Session的最后活跃时间。返回类型为long
int getMaxInactiveInterval() 返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效
void setMaxInactiveInterval(int second) 设置Session的超时时间。单位为秒
void putValue(String attribute, Object value)
不推荐的方法。已经被setAttribute(String attribute, Object Value)替代
Object getValue(String attribute) 不被推荐的方法。已经被getAttribute(String attr)替代
boolean isNew() 返回该Session是否是新创建的
void invalidate() 使该Session失效
Tomcat中Session的默认超时时间为20分钟。通过setMaxInactiveInterval(int seconds)修改超时时间。可以修改web.xml改变Session的默认超时时间。例如修改为60分钟:
<session-config>
<session-timeout>60</session-timeout> <!-- 单位:分钟 -->
</session-config>
注意:<session-timeout>参数的单位为分钟,而setMaxInactiveInterval(int s)单位为秒。
Session对浏览器的要求
虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。
该Cookie为服务器自动生成的,它的maxAge属性一般为-1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。
注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择"在新窗口中打开"时,子窗口便可以访问父窗口的Session。
如果客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另一种解决方案:URL地址重写。
URL地址重写
URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(String url)实现URL地址重写,例如:
<td> <a href="http://www.mamicode.com/<%= response.encodeURL("index.jsp?c=1&wd=Java") %>"> Homepage</a> </td> 该方法会自动判断客户端是否支持Cookie。如果客户端支持Cookie,会将URL原封不动地输出来。如果客户端不支持Cookie,则会将用户Session的id重写到URL中。重写后的输出可能是这样的:
<td> <a href="http://www.mamicode.com/index.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E?c= 1&wd=Java">Homepage</a> </td> 即在文件名的后面,在URL参数的前面添加了字符串";jsessionid=XXX"。其中XXX为Session的id。分析一下可以知道,增添的jsessionid字符串既不会影响请求的文件名,也不会影响提交的地址栏参数。用户单击这个链接的时候会把Session的id通过URL提交到服务器上,服务器通过解析URL地址获得Session的id。
如果是页面重定向(Redirection),URL地址重写可以这样写:
<% if("administrator".equals(userName)){ response.sendRedirect(response.encodeRedirectURL("administrator.jsp")); return; } %> 效果跟response.encodeURL(String url)是一样的:如果客户端支持Cookie,生成原URL地址,如果不支持Cookie,传回重写后的带有jsessionid字符串的地址。
对于WAP程序,由于大部分的手机浏览器都不支持Cookie,WAP程序都会采用URL地址重写来跟踪用户会话。比如用友集团的移动商街等。
注意:TOMCAT判断客户端浏览器是否支持Cookie的依据是请求中是否含有Cookie。尽管客户端可能会支持Cookie,但是由于第一次请求时不会携带任何Cookie(因为并无任何Cookie可以携带),URL地址重写后的地址中仍然会带有jsessionid。当第二次访问时服务器已经在浏览器中写入Cookie了,因此URL地址重写后的地址中就不会带有jsessionid了。
Session中禁止使用Cookie
既然WAP上大部分的客户浏览器都不支持Cookie,索性禁止Session使用Cookie,统一使用URL地址重写会更好一些。Java Web规范支持通过配置的方式禁用Cookie。下面举例说一下怎样通过配置禁止使用Cookie。
打开项目sessionWeb的WebRoot目录下的META-INF文件夹(跟WEB-INF文件夹同级,如果没有则创建),打开context.xml(如果没有则创建),编辑内容如下:
代码5.11 /META-INF/context.xml
<?xml version=‘1.0‘ encoding=‘UTF-8‘?> <Context path="/sessionWeb" cookies="false"> </Context> 或者修改Tomcat全局的conf/context.xml,修改内容如下:
代码5.12 context.xml
<!-- The contents of this file will be loadedfor each web application --> <Context cookies="false"> <!-- ... 中间代码略 --> </Context> 部署后TOMCAT便不会自动生成名JSESSIONID的Cookie,Session也不会以Cookie为识别标志,而仅仅以重写后的URL地址为识别标志了。
注意:该配置只是禁止Session使用Cookie作为识别标志,并不能阻止其他的Cookie读写。也就是说服务器不会自动维护名为JSESSIONID的Cookie了,但是程序中仍然可以读写其他的Cookie。
Session与Cookie的比较
Cookie与Session都可以进行会话跟踪,但是实现的原理不太一样。一般情况下二者均可以满足需求,但有时候不可以使用Cookie,有时候不可以使用Session。下面通过比较说明二者的特点以及适用的场合。
5.3.1 从存取方式上比较
Cookie中只能保存ASCII字符串,如果需要存取Unicode字符或者二进制数据,需要进行UTF-8,GBK或者BASE64等方式的编码。Cookie中也不能直接存取Java对象。若要存储稍微复杂的信息,使用Cookie是比较困难的。
而Session中可以存取任何类型的数据,包括而不限于String、Integer、List、Map等。Session中也可以直接保存Java Bean乃至任何Java类,对象等,使用起来非常方便。可以把Session看做是一个Java容器类。
从隐私安全上比较
Cookie存储在客户端浏览器中,对客户端是可见的,客户端的一些程序可能会窥探、复制甚至修改Cookie中的内容。而Session存储在服务器上,对客户端是透明的,不存在敏感信息泄露的危险。
如果选用Cookie,比较好的办法是,敏感的信息如账号密码等尽量不要写到Cookie中。最好是像Google、Baidu那样将Cookie信息加密,提交到服务器后再进行解密,保证Cookie中的信息只有自己能读得懂。而如果选择Session就省事多了,反正是放在服务器上,Session里任何隐私都可以。
从有效期上比较
使用过Google的人都知道,如果登录过Google,则Google的登录消息长期有效。用户不必每次访问都重新登录,Google会长久地记录该用户的登录信息。要达到这种效果,使用Cookie会是比较好的选择。只需要设置Cookie的maxAge属性为一个很大很大的数字或者Integer.MAX_VALUE就可以了。Cookie的maxAge属性支持这样的效果。
使用Session理论上也能实现这种效果。只要调用方法setMaxInactiveInterval(Integer. MAX_VALUE)不就可以了么。但是由于Session依赖于名为JSESSIONID的Cookie,而Cookie JSESSIONID的maxAge默认为-1,只要关闭了浏览器该Session就会失效,因此Session不能实现信息永久有效的效果。使用URL地址重写也不能实现。
而且如果设置Session的超时时间过长,服务器累计的Session就会越多,越容易导致内存溢出。
从对服务器的负担上比较
Session是保存在服务器端的,每个用户都会产生一个Session。如果并发访问的用户非常多,会产生非常多的Session,消耗大量的内存。因此像Google、Baidu、Sina这样并发访问量极高的网站,是不太可能使用Session来追踪客户会话的。
而Cookie保存在客户端,不占用服务器资源。如果并发浏览的用户非常多,Cookie是很好的选择。对于Google、Baidu、Sina来说,Cookie也许是唯一的选择。
从浏览器支持上比较
Cookie是需要客户端浏览器支持的。如果客户端禁用了Cookie,或者不支持Cookie,则会话跟踪会失效。对于WAP上的应用,常规的Cookie就派不上用场了。
如果客户端浏览器不支持Cookie,需要使用Session以及URL地址重写。需要注意的是所有的用到Session程序的URL都要使用response.encodeURL(String URL)或者response.encodeRedirectURL(String URL)进行URL地址重写,否则导致Session会话跟踪失败。对于WAP应用来说,Session+URL地址重写也许是它唯一的选择。
如果客户端支持Cookie,则Cookie既可以设为本浏览器窗口以及子窗口内有效(把maxAge设为-1),也可以设为所有浏览器窗口内有效(把maxAge设为某个大于0的整数)。但Session只能在本浏览器窗口以及其子窗口内有效。如果两个浏览器窗口互不相干,它们将使用两个不同的Session。
从跨域名上比较
Cookie支持跨域名访问,例如将domain属性设置为".helloweenvsfei.com",则以".helloweenvsfei.com"为后缀的所有域名均可以访问该Cookie。跨域名Cookie现在被广泛用在网络中,例如Google、Baidu、Sina等。而Session则不会支持跨域名访问。Session仅在他所在的域名内有效。
注意:仅使用Cookie或者仅使用Session可能实现不了理想的效果。这时应该尝试一下同时使用Cookie与Session。Cookie与Session的搭配使用在实际项目中会实现绚烂多姿的效果。
本章小结
Cookie是早期的会话跟踪技术,它将信息保存到客户端浏览器中。浏览器访问网站时会携带这些Cookie信息,达到鉴别身份的目的。
Session是在Cookie基础上建立的会话跟踪技术,它将信息保存在服务器端,Session中能够存储负责的Java对象,因此使用更加方便。Session依赖于名为JSESSIONID的Cookie。
如果客户端浏览器不支持Cookie,或者禁用了Cookie,仍然可以通过使用URL地址重写来使用Session。
session生命周期