1. Session模型:
1) HTTP协议是无状态的,无法记录多次请求/响应之间的联系,而Session模型就好比一个中间人,可以帮助使用HTTP协议通信的双方记录每次通信的内容(即会话的内容),因此Session模型就是一种中间人模型,可以保存通信记录;
2) HttpSession对Session模型的实现:
i. 当客户端第一次请求服务器时服务器可以主动建立一个HttpSession对象专门用于记录该客户端和自己这一次,包括今后将要发生的多次,通信记录,建立HttpSession就是建立会话,这种会话(会话对象)可以长期保存;
ii. Web容器会为每个会话分配一个唯一的ID号,容器会将相关通信记录都保存在相应ID的会话对象中,并可以将这些会话对象长期保存在Web容器中(服务器端);
iii. 而Servlet响应客户端时只需要将相应会话的ID保存在Cookie中返回即可,而浏览器下次再请求时只需要凭Cookie中的会话对象的ID让Web容器调出保存在其中的会话对象即可;
3) 大致模型就是:
客户端(Cookie:Session ID) <====> 服务器端(很多Session对象)
!服务器根据客户端请求Cookie中的Session ID调出保存在Web容器中相应的Session对象,然后取出对象中保存的前几次通信的记录并利用!
2. 使用HttpSession的基本流程:
1) 建立或获取Session对象要使用HttpServletRequest的getSession函数:
i. HttpSession HttpServletRequest.getSession(); // 如果通信双方建立过会话则返回之前保存在Web容器中的会话,否则就建立一个新的会话
ii. HttpSession HttpServletRequest.getSession(boolean create); // true就和getSession等价,而false在没有建立过会话的条件下返回null,否则返回相应的会话
!!通常使用前者较多;
2) 插入和提取会话记录:
i. 插入会话记录使用HttpSession的setAttribute,提取会话记录使用getAttribute,用法和HttpServletRequest的setAttribute和getAttribute一模一样,会话记录也是以“键值对”的形式保存;
ii. Object HttpSession.getAttribute(String name); // 提取相应参数名的对象
iii. void HttpSession.setAttribute(String name, Object value); // 设置键值对
!!会话记录都是以类对象的形式保存的,提取出来需要类型转换一下才能放心使用;
2. 会话模型的具体实现:
1) 在建立Session的时候Web容器会为每个Session分配一个唯一的ID号,因此一个HttpSession对象中保存有ID号和各个键值对(会话记录);
2) Session对象都保存在Web容器中;
3) 在响应客户端时Web容器会自动把本次通信的Session的ID加入到Cookie中返回给客户端,其在set-cookie标头中的参数名为JSESSIONID(在Tomcat中是这样),例如:set-cookie: k1=v1; k2=v2…JSESSIONID=C8D2S02LA23…kn=vn….
4) 客户端和服务器端通信只传送Session的ID而不传送Session中的通信记录,当服务器端收到客户端请求并调用getSession时,就会根据请求Cookie中的Session ID从Web容器缓存中调出相应的Session对象,这样通信时就能节省很多容量资源,加大网络流量的利用率同时提高效率,只不过通信记录都是保存在服务器端的,因此服务器端的存储压力较大;
3. HttpSession的常用方法以及配置:
1) 获取Session的ID:String getId();
2) 设置Session的存活期限:void setMaxInactiveInterval(int interval); // 设置请求间隔时间(单位是秒),当浏览器超出interval秒还没有请求该应用的话就清除该Session(释放内存)
!!如果interval为0或负则表示Session可以无限存活(除非关闭Web容器);
!!由于用服务器来保存通信记录是非常消耗内存资源的,因此建议不要将大型对象保存在Session中,如果Session中的对象较大那么设置存活期限就相当必要,否则会导致内存不足降低服务效率;
3) 在web.xml中配置Session的默认存活时间:如果没有调用setMaxInactiveInterval则使用web.xml中的默认值,否则就使用程序中设置的值
i. 所有关于Session的配置都放在<web-app>的<session-config>中;
ii. 存活时间的配置标签是<session-timeout>,但是单位是分钟!!!和set函数单位是秒不一样,千万别搞错了!!
iii. 示例:
-
...
-
<web-app>
-
...
-
<session-config>
-
<session-timeout>30
</session-timeout>
-
</session-config>
-
...
-
</web-app>
-
...
!!!这里设置的是30分钟而不是30秒;
3) Session ID的Cookie配置:
i. 默认情况下,Web容器自动为Session建立的传送ID的Cookie的max-age(Cookie存活时长)为“退出时长”,“退出时常”是指Cookie的存活时间为从创建到浏览器关闭那么久,一旦浏览器退出那么该Cookie就会被清除,不会保存到下次浏览器打开;
ii. 因此在默认情况下,浏览器退出再打开后再次请求该网站,那么请求Cookie中就没有Session ID的信息了,那么服务器端使用getSession时就没有ID可以查找,那么此时就会创建一个新的Session,因此之前的通信记录就无法再获取了,即使记录前几次通信记录的Session对象还可能存活在Web容器的缓存中,但是由于调出该对象的请求不复存在了,因此该Session也只能深埋在缓存中直到达到存活期限被销毁;
iii. 所以我们希望修改Session ID的Cookie的存活时间,关于Session ID的Cookie的配置可以在web.xml中进行:
a. 在<session-config>标签下的<cookie-config>中配置即可;
b. <name>标签可以设置Cookie的名称,可以将默认的JSESSIONID的名称改成其它你想要的;
c. <max-age>标签可以修改Cookie的存活时间,单位为秒;
d. 示例:
-
<session-config>
-
<session-timeout>30
</session-timeout>
-
<cookie-config>
-
<name>SID
</name>
-
<max-age>5000
</max-age>
-
</cookie-config>
-
</session-config>
4) 使Session对象立即无效(Web容器会立即销毁该对象并回收其内存空间):void invalidate();
!!调用后不得在使用其它函数获取、修改Session中的信息,因为其空间已经被回收了,更不能再次invalidate,因为此时引用已经和对象脱钩,如果发生以上任何一种行为都会引发指针异常并抛出IllegalStateException异常;
!!这就相当于C++中手动调用析构函数;