tomcat源码解读六 tomcat中的session生命历程
来源:互联网 发布:暨南大学博士知乎 编辑:程序博客网 时间:2024/06/10 16:20
session的作用是在一次会话中(从打开浏览器到关闭浏览器同当前服务器的交流)当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象,当浏览器下次(session继续有效时)请求别的资源的时候,浏览器会sessionID放置到请求头中,服务器接收到请求后就得到该请求的sessionID,服务器根据当前sessionId找到对应的session实例。
1.1 UML关系图
1.2 Session的获取api
session的创建与tomcat请求没有什么很大的直接关系,主要是在进行servlet处理(jsp最终也是被编译成servlet)来获取,获取方式如下:
/获取此次会话的session//如果参数为true表明当没有获取到对应的session实例会自己创建一个,且默认为真HttpSession session = request.getSession(true);HttpSession session1 = request.getSession();//如果参数为false表明当没有获取到对应的session实例则会返回空HttpSession session2 = request.getSession(false);
1.3 sessionId的获取
这里是在request请求已经解析了头部的情况下,根据配置文件获取相应的参数最终得到sessionId的值,这个值得优先级是URL>cookie 最终这个值将会注册到request属性中去
/** * 这段代码的意义:向request中注入requestedSessionId并设置其是来与URL Cookie 还是SSL * 具体判断是通过requestedSessionURL和requestedSessionSSL这些布尔类型 * 另一个作用是在下文的重定向过程决定是否需要将sessionCookieName给加入进去以;XXX=XXXXXX形式 * 在域名泛解析过程中针对访问不同的二级域名,sessionId是默认不共享的 * */String sessionID;if (request.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.URL)) { //根据当前sessionCookieName从request的参数中获取相应sessionId, sessionID = request.getPathParameter(SessionConfig.getSessionUriParamName(request.getContext())); //如果sessionId不为空,将其注入request的requestedSessionId属性 if (sessionID != null) { request.setRequestedSessionId(sessionID); //获取解析到说明请求是从URL中解析出来 request.setRequestedSessionURL(true); }}//在cookies和SSL中寻找sessionId,如果requestedSessionId不存在,则直接注入parseSessionCookiesId(request);parseSessionSslId(request);sessionID = request.getRequestedSessionId();
这里会有个问题,在URL中都是以k,v的形式存在,那么这个k是来自于哪个地方,一下代码展示:
* 获取配置的sessionCookieName * 第一种是配置Web应用的时候 Context标签下 * 1 <Context path='' docBase='ROOT' sessionCookiePath='/' sessionCookieName='' /> * 2 <session-config> * <cookie-config> * <name id="sessionId">sessionName</name> * </cookie-config> * </session-config> * */private static String getConfiguredSessionCookieName(Context context) { // Priority is: // 1. Cookie name defined in context // 2. Cookie name configured for app // 3. Default defined by spec if (context != null) { //获取sessionCookieName,这个来自于解析自己的Context标签 String cookieName = context.getSessionCookieName(); if (cookieName != null && cookieName.length() > 0) { return cookieName; } //获取定义在应用的中的web.xml session-config/cookie-config SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig(); cookieName = scc.getName(); if (cookieName != null && cookieName.length() > 0) { return cookieName; } } return null;}
根据代码可以看出k可以是在配置Context应用的时候添加,也可以是在web.xml配置,这样就可以获取对应的sessionId。那么这个sessionId使用户自己产生还是怎么来的?一般直接在URL上添加,或者可以通过过滤器等方式将请求进行处理,由于缺少具体开发环境所以不能够很全面的解述.针对在URL上处理会有一个问题,就是重定向,这样不必担心,因为在CoyoteAdapter.java中对重定向处理会获取URL中是否存在,如果存在则直接添加, 代码如下:
MessageBytes redirectPathMB = request.getMappingData().redirectPath;if (!redirectPathMB.isNull()) { String redirectPath = URLEncoder.DEFAULT.encode(redirectPathMB.toString(), "UTF-8"); String query = request.getQueryString(); //如果SessionId是从URL中解析出来的,则直接添加到URL上面 if (request.isRequestedSessionIdFromURL()) { redirectPath = redirectPath + ";" + SessionConfig.getSessionUriParamName( request.getContext()) + "=" + request.getRequestedSessionId(); } //添加参数 if (query != null) { redirectPath = redirectPath + "?" + query; } response.sendRedirect(redirectPath); request.getContext().logAccess(request, response, 0, true); return false;}
1.4 session的实例化过程
session的实例化是在具体的Servlet方法中,调用getSession的API之后,首先是利用门面模式获取到真正的Connector/Request,而后其方法如下:
/**返回与当前请求相关的session*/@Overridepublic HttpSession getSession(boolean create) { //创建session的核心方法 Session session = doGetSession(create); if (session == null) { return null; } return session.getSession();}
在这个方法中首先调用doGetSession在这个过程中我们创建了HttpSession(利用了门面模式)然后将其作为StandardSession的句柄,最终返回的是StandardSession实例,利用其getSession获取对应的HttpSession即我们所需要的session, doGetSession的方法如下
protected Session doGetSession(boolean create) { //获取与当前请求对应的Context Context context = getContext(); if (context == null) { return (null); } /** * 如果存在session并且可利用则直接返回,如果不可利用则将session置为空 * 不可利用是在request的recycle中设置为不可利用 */ if ((session != null) && !session.isValid()) { session = null; } if (session != null) { return (session); } //获取会话管理器 Manager manager = context.getManager(); if (manager == null) { return (null); // Sessions are not supported } if (requestedSessionId != null) { try { //根据sessionId从会话管理器中找到对应session session = manager.findSession(requestedSessionId); } catch (IOException e) { session = null; } if ((session != null) && !session.isValid()) { session = null; } if (session != null) { session.access(); return (session); } } //session为false表示如果没有获取到对应session则直接返回空 if (!create) { return (null); } if (response != null && context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE) && response.getResponse().isCommitted()) { throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted")); } //获取客户端提供的sessionId String sessionId = getRequestedSessionId(); if (requestedSessionSSL) { //在server.xml文件中配置sessionCookiePath="/",并且该sessionId来自于cookie } else if (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie())) { if (context.getValidateClientProvidedNewSessionId()) { boolean found = false; /** * 找到当前主机下所有的web应用获取其会话管理器 * 从对应会话管理器中找若找到相应sessionId不为空,则跳出循环 * * 这样做的目的是可能在不同web应用中sessionId需要保持相同 * 多个web应用构成一个整体的项目 */ for (Container container : getHost().findChildren()) { Manager m = ((Context) container).getManager(); if (m != null) { try { if (m.findSession(sessionId) != null) { found = true; break; } } catch (IOException e) { } } } //如果没有发现则sessionId置为空,表明当前sessionId没有被任何会话管理器使用 if (!found) { sessionId = null; } } } else { sessionId = null; } //创建一个sessionId session = manager.createSession(sessionId); //将session添加到cookie中去 利用Set-Cookie将其添加到HTTP首部 if (session != null && context.getServletContext().getEffectiveSessionTrackingModes() .contains(SessionTrackingMode.COOKIE)) { Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie( context, session.getIdInternal(), isSecure()); response.addSessionCookieInternal(cookie); } if (session == null) { return null; } session.access(); return session;}
- tomcat源码解读六 tomcat中的session生命历程
- tomcat源码解读五 Tomcat中Request的生命历程
- tomcat源码解读四 tomcat中的processer
- tomcat源码解读二 tomcat的生命周期
- tomcat中的session管理
- tomcat中的session管理
- Tomcat中的Session小结
- Tomcat中的Session小结
- Tomcat中的Session小结
- Tomcat中的Session小结
- Tomcat中的Session小结
- tomcat源码阅读步骤六
- 解读tomcat源码之tomcat的启动过程
- tomcat源码解读三(1) tomcat的jmx管理
- 深度解读Tomcat中的NIO模型
- 深度解读 Tomcat 中的 NIO 模型
- 深度解读 Tomcat 中的 NIO 模型
- Tomcat 源码阅读(六)Adapter
- leetcode 441--Arranging Coins
- springmvc注解之@component注解
- mac更新系统后Git不能用,提示missing xcrun at
- 嵌入式软件工程师经典面试题
- 安卓 补间动画代码添加
- tomcat源码解读六 tomcat中的session生命历程
- PHP中使用CURL实现GET和POST请求
- linux _setup()
- Python 大文件读取
- C语言编程需要注意的64位和32机器的区别
- [leetcode]解决Climbing Stairs的一点小心得
- webrtc 码率设置
- Freemarker生成乱码解决
- localStorage