- 浏览: 208123 次
- 性别:
- 来自: 福建省
文章分类
最新评论
-
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 7285一,web服务器小论 以前的公司使用的web服务器是to ... -
Apache实现Tomcat集群
2010-06-08 20:14 1428一,配置介绍 1,linux 2,tomcat6. ... -
Tomcat源码---容器生命周期管理(Lifecycle)一
2010-03-31 11:12 4463一,tomcat中每一个容器 ... -
Tomcat源码---响应处理五
2010-03-25 16:01 1862一,响应工作我们应该从CoyoteAdapter#servic ... -
Tomcat源码---请求处理四(2)
2010-03-25 15:34 1612对以上的StandardWrapperValve#invok ... -
Tomcat源码---请求处理四(1)
2010-03-25 11:08 1642一,现在到了StandardWrapperValve# ... -
Tomcat源码---请求处理三
2010-03-25 10:39 1368一,这一章节主要讲request与response通过管道,阀 ... -
Tomcat源码---请求处理二
2010-03-24 15:04 1840一,经过以上文章(JIoEndpoint$Worker#run ... -
Tomcat源码---请求处理(接收,线程分配)一
2010-03-24 14:34 2824一,在以上文章中tomcat启动已经完毕,接着要做的是消息的请 ... -
Tomcat源码---容器启动六(4)
2010-03-24 11:14 1468现在容器已经启动成功的StanderService#start ... -
Tomcat源码---容器启动六(3)
2010-03-24 10:48 2291一,容器已经启动到部暑文件(webapps),接下去是Stan ... -
Tomcat源码---容器启动六(2)
2010-03-23 16:42 1501super.start()--->org.apach ... -
Tomcat源码---容器启动六(1)
2010-03-22 16:02 1528一,完成了以上的初始化工作,现在进行容器的启动工作由 ... -
Tomcat源码---初始化容器五
2010-03-22 15:03 1826一,上面文章完成了对server.xml载入以及解析,现在主要 ... -
Tomcat源码---载入相应的资源及解析四(2)
2010-03-19 16:47 1512一,根据以上文章所讲的对server.xml的解析作下简单的分 ... -
Tomat源码---载入相应的资源及解析四(1)
2010-03-19 16:22 1404一,进行了以上的类包加载后,现在主要的工作是载入server. ... -
Tomcat源码---启动.初始化(加载类包)分析三
2010-03-19 15:37 2223一,启动 Tomcat是从org.apache.catali ... -
Tomcat的简单了解二
2010-03-19 14:40 1834在查看源代码时,在网上找了一系列的文章,在些作详解: ... -
Tomcat中server.xml的配置分析一
2010-03-19 14:07 1818最近查看了tomcat6的源代码,了解了里面的大概 ...
相关推荐
《深入解析Tomcat-Redis-Session-Manager源码》 在现代Web应用中,服务器端会话管理是一个至关重要的部分,特别是在高并发、分布式环境中。Tomcat作为最流行的Java Servlet容器,提供了丰富的功能来支持这一需求。...
标题中的“Tomcat8亲测可用 tomcat-redis-session-manager的jar包”指的是一个专为Tomcat8设计的,用于管理session的扩展组件。这个组件实现了将Tomcat应用服务器中的用户session数据存储到Redis分布式缓存系统中,...
这个包里含有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 将源码编译后的包。
标题 "tomcat8-redis-session共享" 涉及到的是在Tomcat 8中使用Redis作为Session共享存储的解决方案。这是一个常见的需求,特别是在分布式系统中,为了保持用户会话的一致性,需要将Session数据在多台服务器之间共享...
"tomcat-redis-session-manager-master" 是一个项目名称,表明这是一个与Tomcat(一个流行的Java应用服务器)和Redis(一个开源的内存数据结构存储系统)相关的session管理器的主分支。通常,这样的项目是用来实现将...
自己通过源码编译后的jar包,已实验可以正常使用
tomcat8下 tomcat-redis-session-manager , github上有源码,其他版本都有打好的jar包,tomcat 8 下没有,下载源码生成了一个。
通过上述分析,我们可以看到,Tomcat Redis Session Manager提供了便捷的session共享机制,有效地解决了高并发场景下的session管理问题。通过对源码的学习和实践,开发者可以更好地理解和掌握这一技术,提升系统的可...
Tomcat集群Redis会话管理器 Redis会话管理器是可插入的。 它将会话存储到Redis中,以便在Tomcat服务器群集之间轻松分配HTTP请求。 在这里,会话被实现为非粘性的(意味着,每个请求都可以转到集群中的任何服务器,...
【描述】:“Tomcat集群Nginx使用Redis保证Session同步”这一场景中,通常是因为在多台Tomcat服务器组成的集群中,每个服务器各自维护独立的Session,当用户在集群中的不同服务器之间切换时,可能会导致Session丢失...
通过分析源码,我们可以看到它如何将Tomcat的session操作转化为对Redis的操作。例如,session的创建、读取、更新和删除等操作都会映射到Redis的对应命令。同时,源码中还可能包含了错误处理和性能优化的策略,这些都...
在构建高性能、高可用性的Web应用系统中,session共享是一个重要的环节,特别是在使用负载均衡和应用集群时。本文将详细讲解如何通过Redis实现Tomcat7的session共享,并介绍相关配置和依赖包。首先,我们来看一下...
`tomcat-redis-session`是针对Apache Tomcat服务器的一个插件,它的主要作用是将用户的session信息从Tomcat的内存中移出,存储到高性能的键值存储系统Redis中。这种架构使得session数据可以在多台Tomcat服务器之间...
描述提到的是一个基于"tomcat-redis-session-manager"源码编译生成的jar包,这意味着开发者或系统管理员可以直接将这个jar包引入到他们的Tomcat环境中,无需自己从源代码构建。压缩包内包含了针对Tomcat7和Tomcat8两...
这个项目提供了一个兼容不同Tomcat版本的Session管理器,使得我们可以方便地在不同版本的Tomcat上实现Session共享。 源码可以帮助我们深入了解Session共享的具体实现,包括如何序列化和反序列化Session对象,如何...
深入Tomcat源码,我们可以学习到以下关键知识点: 1. **Web应用部署**:Tomcat如何解析`WEB-INF/web.xml`配置文件,加载Servlet和Filter,以及如何根据`META-INF/context.xml`设置上下文参数。 2. **生命周期管理*...
Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...