关于Java Servlet Session的一些不可不知的知识

概述

说到session大家应该都很熟悉了,session这个概念也是很多J2EE面试题跑不了的一个点。这里不说面试题,只是说一些session的关键知识,有这些知识,相信遇到问题时就能知道该怎么解决了。

session创建时间和保存位置

session概念就是每次会话中创建的会话相关信息。可实质上是一个内存对象,关键的一个是sessionId,一个是attributes。
关于Java Servlet Session的一些不可不知的知识_第1张图片
sessionId是一个唯一标识,一个id对应到一个session。attributes是一个Map,用来存储和session相关的任何信息。看到了这里是一个ConcurrentHashMap,因为一个会话期会有很多的请求,所以这里用的是并发容器。

session是在什么时候创建的呢?这里比较常见的误解是,会话开始session就被创建。其实服务器设计的都很节约资源,只有你在调用request.getSession()的时候,服务器才会创建session对象,并将sessionId返回给前台,保存在cookie中。session对象保存在服务器内存中。

一旦创建过session,那么同一会话中的所有请求,都会由浏览器自动的在请求头中加上这个sessionId。当服务器接收到请求,并通过request.getSession()获取session时,实质上是依据请求头中的sessionId从内存中取到已经保存的同一个会话(session对象)。

可以用下面的图,更清晰的描述一下这个过程:
关于Java Servlet Session的一些不可不知的知识_第2张图片

由于session中有一个attributes的map容器,所以我们可以放入用户登录、用户权限等信息。使用下面的方法:

存储
request.getSession().setAttribute(“userInfo”,user);

获取
UserInfo user = (UserInfo)request.getSession().getAttribute(“userInfo”);

一次会话中为什么session能够保持不变

从session的保存位置,大家应该明白只要前端保存的JSESSIONID的cookie值是一个值,那么所有的请求都会获取到同一个session对象,也就是获取到的数据一致。

session是会话的意思,在同一个会话中所有的请求都对应到同一个session对象,这时浏览器和服务器共同承诺的。那么怎么算是同一个会话呢?

一般来说同一个浏览器对于同一个站点的请求都算是同一个话,只要会话没有超时,没有调用invalidate销毁,服务器中途没有关闭过,那么你下一次请求获取到的一定是同一个session。

上一段说到的三个只要,也就是使session失效的3种方式。当然,如果session被保存到了数据库或者memecached,redis等存储中,那么中途重启服务器,也不会造成session失效。

session在同一个会话中一直变是什么鬼

有时候你会遇到这种情况,明明实在同一个浏览器,访问同一个站点,但是每次取到的session居然不一样。明明就是在一个会话中的多次请求,但是session就是不一样,之前存进去到session里面的数据,后续的请求死活拿不到。

这个问题,还是要回过头来看session存储位置,要保持session在同一个会话中不变,那么浏览器端保存的JSESSIONID也是很重要的。但是现在很多浏览器默认或者被认为设置了cookie禁用,那么JSESSIONID就保存不了,自然服务端就不能识别出多次请求属于同一个会话了。

常见的IE和safari比较常见,这种问题。要解决这个问题,有两种方案:1.自己的站点替代浏览器管理JSESSIONID信息;2.提示用户打开cookie,比如京东这样:

关于Java Servlet Session的一些不可不知的知识_第3张图片

分布式环境中使用session保存用户信息

在分布式系统中,我们总是会有多台服务器,同一个用户的请求,有些分配到了a-server,有些分配到了b-server,由于session对象是保存在服务器内存里面的。

假设用户在的登录请求被分配到了a-server,后续的请求分到了b-server,那么b-server中通过a-server生成的sessionId必然找不到对应的session对象了,这时候怎么办呢?

方法有两种:1.session共享,所有服务器生成的session都保存到同一个位置;2.session保持,同一个sessionid的请求分发给同一台服务器处理。

session共享可以在服务器层面做,tomcat、websphere、httpd等;也可以在应用层面做,比如spring-session。

session保持只能在负载均衡处做工作,比如nginx的session保持。nginx做session保持可以用ip_hash,也可以用sticky_cookie_insert。可以参见http://www.etwiki.cn/linux/1773.html

当使用了session共享之后

之前有一个小问题,稍微迷糊了我一下。就是:既然多个后端服务器,同时向memecached或者redis或者数据库中持久化了session,那么在页面上的多个请求被分配到不同的后端服务器后,必然由于并发原因,会生成不同的session对象,并在存储中产生对个session对象。

那么,怎么避免这种情况呢?需不需要自己做同步处理呢?还是说session共享的模块做了共享锁一类的处理,或者是实际上有一个串行化的模块在起着作用呢?

实质上,没有锁,也没有串行化,会持久化多个不同的session也是完全正确的。但是,这对请求完全没有影响,因为在后续的登录请求发生时,必然会从cookie中取出JSESSIONID放到请求头,发送给后端,不论后端几个服务器在处理,前端给的永远是一个JSESSIONID,这个值和登录请求发送时的值一致。

所以,并发完全不影响最终结果和效果的正确。

你可能感兴趣的:(移动应用JAVA后台开发)