- 浏览: 204400 次
- 性别:
- 来自: 福建省
文章分类
最新评论
-
c929833623:
...
Mysql JDBC驱动源码分析(Statement,ResultSet的创建)四 -
pythonlord:
顶 很有帮助,感谢楼主,好人一生平安
Mysql JDBC驱动源码分析(加载驱动)一 -
kiaonly:
代码有错误,我戳。
解释器模式(Interpreter)---java与模式(例子) -
wyzxzws:
小鸟学习了!
JAVA编码问题记录 -
xiaotao.2010:
写的不错! 弱弱说一句 建议使用URL二次转码, 这样可以避免 ...
JAVA编码问题记录
一,前面看了大致的tomcat的请求/响应,接下来的文章对tomcat里面的一些模块进行详细分析,从中学习其思想...
Session的功能(Session 对象可以存储特定用户会话所需的信息):
1,session是一个以bean的形式存在的,存储在内存中,特定用户可对其进行crud操作.
2,session是有生命周期的.
3,sesson是通过特定用户访问系统时,返回给一个jsessionid来进行识别用户的
----------------------------------------------------------------------------------------------------------------------
1,当客户端发送请求时,如果在头部文件中有传送jsessionid(生成jsessionid是在下面一部分讲),则执行以下步骤
执行到请求时会执行这个方法CoyoteAdapter#service...方法下的这步时if (postParseRequest(req, request, res, response))
对sessionid进行了操作,如下:
/** * Parse additional request parameters. */ protected boolean postParseRequest(org.apache.coyote.Request req, Request request, org.apache.coyote.Response res, Response response) throws Exception { //代码略 // Parse session Id(解析;url=;jsessionid=) parseSessionId(req, request); //代码略 // Parse session Id(解决cookie中所带的jsessionid=) parseSessionCookiesId(req, request); return true; }
1,parseSessiond(req,request)
/**
* Parse session id in URL. */ protected void parseSessionId(org.apache.coyote.Request req, Request request) { ByteChunk uriBC = req.requestURI().getByteChunk(); //分析url上是否带有jsessionid int semicolon = uriBC.indexOf(match, 0, match.length(), 0); if (semicolon > 0) { // Parse session ID, and extract it from the decoded request URI int start = uriBC.getStart(); int end = uriBC.getEnd(); int sessionIdStart = semicolon + match.length(); int semicolon2 = uriBC.indexOf(';', sessionIdStart); if (semicolon2 >= 0) { request.setRequestedSessionId (new String(uriBC.getBuffer(), start + sessionIdStart, semicolon2 - sessionIdStart)); // Extract session ID from request URI byte[] buf = uriBC.getBuffer(); for (int i = 0; i < end - start - semicolon2; i++) { buf[start + semicolon + i] = buf[start + i + semicolon2]; } uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon); } else { request.setRequestedSessionId (new String(uriBC.getBuffer(), start + sessionIdStart, (end - start) - sessionIdStart)); uriBC.setEnd(start + semicolon); } //如果有jsessionid,设置到request中 request.setRequestedSessionURL(true); } else { request.setRequestedSessionId(null); request.setRequestedSessionURL(false); } }
2,parseSessionCookiesId(req, request);
/** * Parse session id in cookie */ protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { // If session tracking via cookies has been disabled for the current // context, don't go looking for a session ID in a cookie as a cookie // from a parent context with a session ID may be present which would // overwrite the valid session ID encoded in the URL Context context = (Context) request.getMappingData().context; if (context != null && !context.getCookies()) return; // Parse session id from cookies //获取cookies Cookies serverCookies = req.getCookies(); int count = serverCookies.getCookieCount(); if (count <= 0) return; for (int i = 0; i < count; i++) { ServerCookie scookie = serverCookies.getCookie(i); if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) { // Override anything requested in the URL if (!request.isRequestedSessionIdFromCookie()) { // Accept only the first session id cookie convertMB(scookie.getValue()); request.setRequestedSessionId (scookie.getValue().toString()); request.setRequestedSessionCookie(true); request.setRequestedSessionURL(false); if (log.isDebugEnabled()) log.debug(" Requested cookie session id is " + request.getRequestedSessionId()); } else { if (!request.isRequestedSessionIdValid()) { // Replace the session id until one is valid convertMB(scookie.getValue()); //在进行查找jsessionid如果有的话,设置进request request.setRequestedSessionId (scookie.getValue().toString()); } } } } }
由以上可知如果客户端有访问过系统的话,客户端的jsessionid将被设置进request中
----------------------------------------------------------------------------------------
在StandardManager是用来管理Session类的,首先是StandardManager的实例化是在
StandardContext#start
// Acquire clustered manager Manager contextManager = null; if (manager == null) { if ( (getCluster() != null) && distributable) { try { contextManager = getCluster().createManager(getName()); } catch (Exception ex) { log.error("standardContext.clusterFail", ex); ok = false; } } else { contextManager = new StandardManager(); } }
-------------------------------------------------------------------------------
现在查看的是Session的生成过程..request.getSession()
/** * Return the session associated with this Request, creating one * if necessary. */ public HttpSession getSession() { Session session = doGetSession(true); if (session != null) { return session.getSession(); } else { return null; } }
doGetSession(true)
protected Session doGetSession(boolean create) { // There cannot be a session if no context has been assigned yet if (context == null) return (null); // Return the current session if it exists and is valid if ((session != null) && !session.isValid()) session = null; if (session != null) return (session); // Return the requested session if it exists and is valid //StandardContext#start时进行的初始化 Manager manager = null; if (context != null) manager = context.getManager(); if (manager == null) return (null); // Sessions are not supported if (requestedSessionId != null) { try { //不为空的话,进行查找 session = manager.findSession(requestedSessionId); } catch (IOException e) { session = null; } if ((session != null) && !session.isValid()) session = null; if (session != null) { //更新时间,使其生命周期重设为30(默认) session.access(); return (session); } } // Create a new session if requested and the response is not committed //进行创建 if (!create) return (null); if ((context != null) && (response != null) && context.getCookies() && response.getResponse().isCommitted()) { throw new IllegalStateException (sm.getString("coyoteRequest.sessionCreateCommitted")); } // Attempt to reuse session id if one was submitted in a cookie // Do not reuse the session id if it is from a URL, to prevent possible // phishing attacks //判断session cookie的存储路径 if (connector.getEmptySessionPath() && isRequestedSessionIdFromCookie()) { //进行创建 session = manager.createSession(getRequestedSessionId()); } else { session = manager.createSession(null); } // Creating a new session cookie based on that session if ((session != null) && (getContext() != null) && getContext().getCookies()) { Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, session.getIdInternal()); configureSessionCookie(cookie); //在响应时,返回session cookie,这样在客户端就接收到一个jsessionid response.addCookieInternal(cookie, context.getUseHttpOnly()); } if (session != null) { //如上 session.access(); return (session); } else { return (null); } }
由上面的代码可以看出,sesion是先查找再创建,,,
ManagerBase#findSession
public Session findSession(String id) throws IOException { if (id == null) return (null); //sessions(ConcurrentHashMap<String, Session>)进行读取 return (Session) sessions.get(id); }
#createSession
public Session createSession(String sessionId) { // Recycle or create a Session instance //进行创建 Session session = createEmptySession(); // Initialize the properties of the new session and return it //进行初始化 session.setNew(true); session.setValid(true); session.setCreationTime(System.currentTimeMillis()); session.setMaxInactiveInterval(this.maxInactiveInterval); if (sessionId == null) { //产生一个jsessionid sessionId = generateSessionId(); // FIXME WHy we need no duplication check? /* synchronized (sessions) { while (sessions.get(sessionId) != null) { // Guarantee // uniqueness duplicates++; //产生一个jsessionid sessionId = generateSessionId(); } } */ // FIXME: Code to be used in case route replacement is needed /* } else { String jvmRoute = getJvmRoute(); if (getJvmRoute() != null) { String requestJvmRoute = null; int index = sessionId.indexOf("."); if (index > 0) { requestJvmRoute = sessionId .substring(index + 1, sessionId.length()); } if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) { sessionId = sessionId.substring(0, index) + "." + jvmRoute; } } */ } session.setId(sessionId); sessionCounter++; return (session);
故一整个流程是:
当客户端有请求session时request.getSession(),并生成一个jsessionid cookie返回给客户端,以后每次访问都得带着这个jsessionid过来,进行对ConcurrentHashMap<String, Session>进行识别.
------------------------------------------------------------------------------------------------------------------
还有一个问题就是当服务器突然中断掉时,重新启动时,未过期的session是可以重新加载的...
StandardManager#start()方法。最后调用了#load()方法.
public void load() throws ClassNotFoundException, IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged( new PrivilegedDoLoad() ); } catch (PrivilegedActionException ex){ Exception exception = ex.getException(); if (exception instanceof ClassNotFoundException){ throw (ClassNotFoundException)exception; } else if (exception instanceof IOException){ throw (IOException)exception; } if (log.isDebugEnabled()) log.debug("Unreported exception in load() " + exception); } } else { doLoad(); } }
# doLoad()
protected void doLoad() throws ClassNotFoundException, IOException { if (log.isDebugEnabled()) log.debug("Start: Loading persisted sessions"); // Initialize our internal data structures sessions.clear(); // Open an input stream to the specified pathname, if any // %CATALINA_HOME%/localhost/%app_name% /SESSIONS.ser文件,每一个应用下都有这个sessions.ser //可以从这里还原未过期的session File file = file(); if (file == null) return; if (log.isDebugEnabled()) log.debug(sm.getString("standardManager.loading", pathname)); FileInputStream fis = null; ObjectInputStream ois = null; Loader loader = null; ClassLoader classLoader = null; try { fis = new FileInputStream(file.getAbsolutePath()); BufferedInputStream bis = new BufferedInputStream(fis); if (container != null) loader = container.getLoader(); if (loader != null) classLoader = loader.getClassLoader(); if (classLoader != null) { if (log.isDebugEnabled()) log.debug("Creating custom object input stream for class loader "); ois = new CustomObjectInputStream(bis, classLoader); } else { if (log.isDebugEnabled()) log.debug("Creating standard object input stream"); ois = new ObjectInputStream(bis); } } catch (FileNotFoundException e) { if (log.isDebugEnabled()) log.debug("No persisted data file found"); return; } catch (IOException e) { log.error(sm.getString("standardManager.loading.ioe", e), e); if (ois != null) { try { ois.close(); } catch (IOException f) { ; } ois = null; } throw e; } // Load the previously unloaded active sessions synchronized (sessions) { try { Integer count = (Integer) ois.readObject(); int n = count.intValue(); if (log.isDebugEnabled()) log.debug("Loading " + n + " persisted sessions"); for (int i = 0; i < n; i++) { StandardSession session = getNewSession(); session.readObjectData(ois); session.setManager(this); sessions.put(session.getIdInternal(), session); session.activate(); sessionCounter++; } } catch (ClassNotFoundException e) { log.error(sm.getString("standardManager.loading.cnfe", e), e); if (ois != null) { try { ois.close(); } catch (IOException f) { ; } ois = null; } throw e; } catch (IOException e) { log.error(sm.getString("standardManager.loading.ioe", e), e); if (ois != null) { try { ois.close(); } catch (IOException f) { ; } ois = null; } throw e; } finally { // Close the input stream try { if (ois != null) ois.close(); } catch (IOException f) { // ignored } // Delete the persistent storage file if (file != null && file.exists() ) file.delete(); } } if (log.isDebugEnabled()) log.debug("Finish: Loading persisted sessions"); }
发表评论
-
Nginx1.1实现Resin4集群
2011-10-17 17:56 7214一,web服务器小论 以前的公司使用的web服务器是to ... -
Apache实现Tomcat集群
2010-06-08 20:14 1389一,配置介绍 1,linux 2,tomcat6. ... -
Tomcat源码---容器生命周期管理(Lifecycle)一
2010-03-31 11:12 4413一,tomcat中每一个容器 ... -
Tomcat源码---响应处理五
2010-03-25 16:01 1784一,响应工作我们应该从CoyoteAdapter#servic ... -
Tomcat源码---请求处理四(2)
2010-03-25 15:34 1582对以上的StandardWrapperValve#invok ... -
Tomcat源码---请求处理四(1)
2010-03-25 11:08 1616一,现在到了StandardWrapperValve# ... -
Tomcat源码---请求处理三
2010-03-25 10:39 1314一,这一章节主要讲request与response通过管道,阀 ... -
Tomcat源码---请求处理二
2010-03-24 15:04 1796一,经过以上文章(JIoEndpoint$Worker#run ... -
Tomcat源码---请求处理(接收,线程分配)一
2010-03-24 14:34 2786一,在以上文章中tomcat启动已经完毕,接着要做的是消息的请 ... -
Tomcat源码---容器启动六(4)
2010-03-24 11:14 1399现在容器已经启动成功的StanderService#start ... -
Tomcat源码---容器启动六(3)
2010-03-24 10:48 2251一,容器已经启动到部暑文件(webapps),接下去是Stan ... -
Tomcat源码---容器启动六(2)
2010-03-23 16:42 1456super.start()--->org.apach ... -
Tomcat源码---容器启动六(1)
2010-03-22 16:02 1455一,完成了以上的初始化工作,现在进行容器的启动工作由 ... -
Tomcat源码---初始化容器五
2010-03-22 15:03 1774一,上面文章完成了对server.xml载入以及解析,现在主要 ... -
Tomcat源码---载入相应的资源及解析四(2)
2010-03-19 16:47 1468一,根据以上文章所讲的对server.xml的解析作下简单的分 ... -
Tomat源码---载入相应的资源及解析四(1)
2010-03-19 16:22 1366一,进行了以上的类包加载后,现在主要的工作是载入server. ... -
Tomcat源码---启动.初始化(加载类包)分析三
2010-03-19 15:37 2193一,启动 Tomcat是从org.apache.catali ... -
Tomcat的简单了解二
2010-03-19 14:40 1798在查看源代码时,在网上找了一系列的文章,在些作详解: ... -
Tomcat中server.xml的配置分析一
2010-03-19 14:07 1781最近查看了tomcat6的源代码,了解了里面的大概 ...
相关推荐
tomcat-redis-session-manager源码
Tomcat8亲测可用 tomcat-redis-session-manager的jar包 修改了tomcat-redis-session-manager源码进行的编译生成的jar包
这个包里含有commons-pool2-2.4.2、jedis-2.9.0、tomcat85-session-redis-1.0三个主要JAR包。apache-tomcat-8.5.20.tar.gz源码包和context.xml文件,这套配置是我自己亲测可用的。。另外我用的redis4这个版本。注意...
因tomcat7使用redis共享session,其他的包存在问题,自己编译后处理通过。 该包是在https://github.com/jcoleman/tomcat-redis-session-manager 将源码编译后的包。
基于tomcat-redis-session-manager源码进行的编译生成的jar包,压缩包中包含Tomcat7和Tomcat8打好的jar包。
自己通过源码编译后的jar包,已实验可以正常使用
tomcat8下 tomcat-redis-session-manager , github上有源码,其他版本都有打好的jar包,tomcat 8 下没有,下载源码生成了一个。
Tomcat集群Redis会话管理器 Redis会话管理器是可插入的。 它将会话存储到Redis中,以便在Tomcat服务器群集之间轻松分配HTTP请求。 在这里,会话被实现为非粘性的(意味着,每个请求都可以转到集群中的任何服务器,...
tomcat-redis-session-manager-master,修改了github上的源码,有三个版本,支持tomcat8.0,tomcat8.5和tomcat9
tomcat 集群 nginx 使用redis 保证session同步
tomcat session共享源码学习
基于tomcat-redis-session-manager源码进行的编译生成的jar包,压缩包中包含Tomcat7和Tomcat8打好的jar包。
我的运行环境是:JDK1.6+TOMCAT6.0.45,MSM加Tomcat有一个特别大的坑是如果Tomcat版本是6.0.45或者7.0.68,应用了MSM后会出现session快速失效的问题,经调试跟踪,发现原来是tomcat的session失效时间传入MSM的时候时间...
基于tomcat-redis-session-manager源码进行的编译生成的jar包,压缩包中包含Tomcat7和Tomcat8打好的jar包。
包含源码和源码编译后的包。
解决race condition问题,根据git最新源码编译
NULL 博文链接:https://acooly.iteye.com/blog/1347417
tomcat8、8.5、9与redis实现session共享,并可以通过修改源码可自定义session键,访问地址:http://blog.csdn.net/fackyou200/article/details/78929008
tomcat8 的集群session共享 案例 亲测可用(代码自己根据tomcat7的session共享的源码jar封装的) 无效联系我:351137017