Session 大家知道是保存用户状态信息的,前端第一次请求后端,后端会生成一个session并返回set-cookie: JSESSIONID=xxxx来标识客户端,等客户端再次访问即可通过JSESSIONID找到服务端对应的session。
比如说登录的时候我们可以把登录的信息放到session中,用户登录过后把用户信息放入到session中,后续的请求都可以从session中获取到当前用户的数据。因为客户端的sessionid是不会重复的所以此时在后端拿到的session也是不会冲突的,各自拿各自的session数据。
在Spring没有做任何配置的时候,默认会使用Tomcat 自带的session来做session机制。比如没有配置SessionRepository 以及 @EnableSpringHttpSession
等等。我们下面来分析一个前端请求过来Springboot是如何处理的。
我们都知道客户端第一次请求过后服务端会返回一个jsessionid回来,但是这个jsessionid是怎么生成的,第二次及以后访问是如何匹配session的呢?我们下面先从session生成的节点来分析。
① Springboot 嵌入式 tomcat 默认采用的是NIO模型,非阻塞IO可以理解为类似Epoll模型linux的多路复用。会将请求交给tomcat线程池中取出的线程进行处理。
Http11NioProtocol
② 任务会交给http处理器进行处理http11NioProcessor
,http11NioProcessor会初始化CoyoteRequest/Respose,这两个对象会在后面执行被封装为HttpServletRequest/Response。
CoyoteAdapter
③ 调用CoyoteAdatpter做适配处理的时候会前置处理sessionid,如果cookies中有jsessionid则取cookies中的jsessionid做requestSessionid,如果没有就会在后续责任链的时候调用RequestFacdes.getSession来手动创建session。
method:
CoyoteAdapter.service
method:
CoyoteAdapter.CoyoteAdapter
① 如果URL中有SESSOINID则取URL中的SESSIONID作为RequestSessionid
② 从cookies中获取sessionid
method:
CoyoteAdapter.parseSessionCookiesId
① 如果cookies count <= 0 则立马返回,不做任何处理,加入客户端在第一次访问服务端的时候这个时候啥Cookies都没有就是这种情况。
② 如果cookies count > 0则获取cookie name 为JSESSIONID的cookie设置为requestSessionid。
如果没做任何配置的话session name 默认的配置是jsessionid。
class:
xxxFilter
在过滤器中使用ServletRequest.getSession()方法的时候会去调用门面方法getSEssion()
method:
RequestFacade.getSession()
可以看到如果没有sessionid的话这个时候会去创建sessionid.最终会去创建session,生成sessionid.
method:ManagerBase.createSession
我们先来讲一下ManagerBase这个类,这个类是用来管理StandardSession的,Session的存储创建,session管理、session过期等等都是这个类负责的。所有的session操作都最终会落到这个manager进行处理(特指tomcat session)。
session.setId的时候会把当前的session放到session的管理map中,这样下次就可以从sessions这个map直接根据sessionid获取session了。
method:
ManagerBase.add
ManagerBase中sessions这个成员变量就是对所有session管理的map。
仔细看下这里创建玩session之后会创建一个timer这个就是负责session过期的timer。
method:ManagerBase.generateSessionId
生成sessionid的算法
那后续的response后会把生成的requestSessionid放入到cookie中返回给前端。前端第二次请求的话,服务端就可以从cookies中获取到jsessionid赋值给requestSessionid。从而从Tomcat维护的MapSession中获取到对应的session,从而实现客户端和服务端的会话保持。
Tomcat session 是如何设置值的?
我们一般都会先获取到session然后再往session的attribute中设置属性值,那我们怎么样在代码中获取到session的呢?
我拿一个最简单例子来举:
我同通过注入HttpServletRequest 或者同xxxContextHolder获取到了Request对象之后,然后根据request对象来获取session。这个时候会进入到RequestFacade.getSession方法中:
和上述的创建sessionid一样,也会进入到doGetSession()方法中
① 之前讲了requestSessionId创建和获取,因为这个时候已经有了requestsessionid和session,直接从sessions里边把对应的session拿出来返回即可。