暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Session系列之二(StandardSession分析)

中间件技术讨论圈 2016-07-26
925

在Tomcat中,HttpSession的实际实现为StandardSession。



1.类接口分析


a.对于该类,首先肯定是要实现HttpSession接口,该接口为JAVA EE规范,关于HttpSession接口的一些方法在上一节中已经讲得很清楚了;

b.其次,StandardSession要实现Tomcat中的Session接口,该接口主要维护Tomcat内部对Session的处理,如SessionId相关,session失效相关处理,Tomcat内部生命周期事件,有效性访问等等,与JAVA EE规范中的HttpSession接口没有关系,而StandardSession是Tomcat中的一个实体组件,所以需要实现该接口


上面的四个事件,是Tomcat的内部事件;

c.除此之外,在后续的分析中,我们可以看到Session在Tomcat中是可以进行持久化的,根据需要所以需要可以进行序列化,实现Serializable;


2.set/getAttributes


可以理解,因为Session中可以存储属性,put,get方法对应的就应该是Map;

而我们第二个反应就是,因为不同的客户端线程在Servlet中操纵Session,因此这肯定是需要并发处理的,因此就是ConcurrentHashmap;

值得说的一点是,在ConcurrentHashmap没出来之前,session访问属性效率较低,当时是通过Hashmap的Synchronized同步化来做的,加一个独占锁,而ConcurrentHashmap是CAS优化,大大提升了效率,我们从这里也可以看到,JDK的升级对服务器的效率提升有质的帮助。



3.sessionId产生原理与实现


在Tomcat中,每一个新创建的Session,都有一个唯一标识的字符串与之相对应,

对于session是如何创建的,这个是由StandardManager来进行管理的,其创建session就是调用其createSession方法:


首先创建一个空StandardSession类,然后设置一些属性,因为是第一次,所以设置New

设置之后,其通过generateSessionId产生SessionId这个唯一标识的字符串;

对于SessionId是怎么产生的呢?


我们暂且不管上面SessionId产生的算法,

我们分析SessionId是由配置的SessionIdLength的长度,随机数+算法,还有一个最重要的参数,JVMRoute来产生的。

什么是JVMRoute呢?

可以理解为这个属性就是tomcat中的路由标识,其作用主要是在tomcat集群中,用以区分两台tomcat主机,一般配置如下:

tomcat1\conf\server.xml

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"> 

tomcat2\conf\server.xml 

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2"> 

这样在集群的过程中,每一台主机的jvmRoute都不同,因而生成的sessionId也会不同,如集群配置为轮询,我们来看看这种情况的

访问http://localhost:8080/1.jsp 可以看到session.getId()的值在原session id后面多了jvmRoute的值。 

ID 46A5843FF4A1E0A84338225AC02F6430.tomcat1 

随意添加key-value,可以看到session信息只在tomcat1中输出。 

再打开一个浏览器,并访问http://localhost:8080/1.jsp 其session id可能变为 

ID 11478E5BE5FE388E4845205B4133A30F.tomcat2 

其值也只会在tomcat2中输出。 

上面的. 后面的内容就是其对应的jvmRoute;


4.sessionId附着和跟踪机制


那么,我们不禁要问,上述的sessionId是如何查看的呢?

Tomcat中一共有几种sessionID附着与跟踪的方式,我们可以从一个Tomcat中的内部类看出来:



a.第一种方式是将sessionId写入到cookie中,客户端和服务器端每一次交互的时候,都从cookie中取出JsessionId,看是否有这个条目,如果存在JSESSIONID的cookies,


在Tomcat前端线程池到Tomcat后端容器的这一个过程中,CoyAdpator会解析对应的参数,并设置到Request中去


然后,Request会基于客户端传递过来的sessionId进行初始化,找寻的办法就是拿客户端的JSESSIONID,去这个查询服务器端前面提到的session的concurrentHashmap中查询


如果查询不到的话,那么说明当前session已经失效了,要重新创建一个Session:


那么最后,也需要在响应头中新建一个cookie,写回到客户端中;


b.第二种方式是采用url重写的session机制

什么是url重写,也就是说当cookie在浏览器端不支持的情况下(现如今一般很少有这样的情况,除非客户端浏览器已经禁用cookie),也就说说,JSESSIONID=xxxx 这段作为一个参数,在客户端访问该站点一直都作为url的尾巴:


这当然比较难看啦,一个超级长的链接,但这种办法也是权益之计,毕竟没有cookie省事,现在cookie不是用不了了吗!


URL重写的检查是放在cookie前面的,可以推断出来,url重写应该是默认支持的模式;

我们不用猜测,直接看一下SessionTrackingMode是怎么定义的:


对于URL重写,从代码上分析,肯定是默认支持;

其次,来判断当前应用Context(StandardContext)是否支持cookie,如果支持的话,在SessionTrackingMode集合中加上这个模式,加上这个模式后,前面的Request的代码中就可以看到,会多一步,在cookie中寻找;


当配置SSL的时候,并且需要在配置文件中配置SSLEnabled的话,SessionTrackingMode才启动SSL模式;

对于SSL交互,其遵循的协议是SSL/TLS了,因此SessionId创建是不同的,这块我们单独在SSL的文章讲解中专题讲座基于SSL 的SessionId;


5.失效与时间

session作为一个有限时间内的缓存,发挥着重要的作用同时,也受时间的限制;

在StandardSession类中,有好几个属性都能解决该Session是否没有效了,我们可以看一个方法就一目了然:


a. isValid属性:对应HttpSession就是invalidate方法,无论session有效期过没过,一下就置为无效


b.expire属性:该属性代表,session已经过期了,


c.ACTIVITY_CHECK:该属性是Tomcat的一个-D开关,其作用可以参考 Tomcat的属性页面的解释:

http://tomcat.apache.org/tomcat-8.5-doc/config/systemprops.html


当设置了这个属性的时候,Tomcat会对session进行计数,从图中也就是accesscount,也就是说在session的范围内,有几个有效的链接是起作用的,当链接过来,accesscount会加1,当关闭链接,accesscount会减1;

这相当于什么?

accesscount实际就是个针对于当前Session的在线活跃数的统计;

回到前面的isValid方法,当accesscount>0,说明当前session活跃用户数肯定不是0,这就意味着当前的session肯定有效;


d.maxInactiveInterval:这个属性是HttpSession的属性,标识着过了多久,客户端的请求连接能让session再续下去,maxInactiveInterval要想起作用,主要就是当前时间-上次记录的时间,


这里就有一个Tomcat的-D参数,其作用就是我们看到access方法,配置的内容是Tomcat中可以怎么掐这段时间:


当上述为true,在access方法刚调用的时候打一个时间戳,也就是thisAccessedTime,当为false,就是lastAccessedTime,在endaccess打一个时间戳;

二者的区别在于不将请求的时间算进去,因为有的时候请求是长事务,占用很长的时间;


总结

StandardSession实际上是Tomcat对session的实现,该类既完全实现了HttpSession接口,又针对Tomcat的内部生命周期事件给出了实现,并且基于SessionId给出了经典的解释,如果我们要自己实现session,这个类是一个非常好的教材!


文章转载自中间件技术讨论圈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论