- 浏览: 1099241 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (379)
- eclipse (6)
- java基础 (21)
- opencms (4)
- tomcat (10)
- kettle (13)
- spring (7)
- 生活点滴 (3)
- linux (61)
- database (1)
- php (4)
- mac (3)
- mysql (37)
- maven (5)
- Asterisk (2)
- android (4)
- birt (2)
- hadoop (52)
- pentaho (46)
- distributed (2)
- Storm (2)
- 数据挖掘 (1)
- cassandra (0)
- spark (0)
- greenplum (3)
- R (1)
- liferay (3)
- 深度学习 (2)
- 数学 (1)
- Docker (3)
- Rancher (2)
- html (1)
- oracle (0)
- 交易 (0)
- Davinci (0)
- 大模型 (0)
最新评论
-
gujunge:
劝退。不支持两步验证登录、复制Session无效
Linux下SecureCRT的替代品:PAC Manager -
huangtianleyuan:
各位大神,有没有集成好的,请不吝赐教 qq:375249222 ...
在Web中集成Kettle -
梦行Monxin商城系统:
Dapper,大规模分布式系统的跟踪系统 -
hunter123456:
您好,请问一下,pentaho5.X 以上的版本,在服务器上建 ...
pentaho 4.8 添加 kettle 文件资源库的支持 -
hunter123456:
你好!pentaho5上 cas 单点登录,除了 修改appl ...
作为一个BI开发人员,我要发布报表,元数据,OLAP的模型到BI服务器
转载自:
http://zddava.iteye.com/blog/311053
http://zddava.iteye.com/blog/311136
管理
Session对象的创建一般是源于这样的一条语句:
Session session = request.getSession(false);或者Session session = request.getSession();如果不在乎服务器压力可能多那么一点点的话。
Session session = request.getSession(false);或者Session session = request.getSession();如果不在乎服务器压力可能多那么一点点的话。
在Tomcat的实现中,这个request是org.apache.catalina.connector.Request类的包装类 org.apache.catalina.connector.RequestFacade的对象,它的两个#getSession()方法如下:
public HttpSession getSession(boolean create) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (SecurityUtil.isPackageProtectionEnabled()){ return (HttpSession)AccessController. doPrivileged(new GetSessionPrivilegedAction(create)); } else { return request.getSession(create); } }
public HttpSession getSession() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return getSession(true); }其实差不太多,最后都会进入org.apache.catalina.connector.Request的#getSession()方法。这个方法的源代码如下:
public HttpSession getSession(boolean create) { Session session = doGetSession(create); if (session != null) { return session.getSession(); } else { return null; } }然后调用就到了#doGetSession()这个方法了。源代码如下
protected Session doGetSession(boolean create) { // 没有Context的话直接返回null if (context == null) return (null); // 判断Session是否有效 if ((session != null) && !session.isValid()) session = null; if (session != null) return (session); // 返回Manager对象,这里是StandardManager类的对象 Manager manager = null; if (context != null) manager = context.getManager(); if (manager == null) return (null); // Sessions are not supported // 判断是否有SessionID if (requestedSessionId != null) { try { // 在Manager中根据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 if (!create) return (null); if ((context != null) && (response != null) && context.getCookies() && response.getResponse().isCommitted()) { throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted")); } // 判断是否使用 "/" 作为Session Cookie的存储路径 并且 是否SessionID来自Cookie if (connector.getEmptySessionPath() && isRequestedSessionIdFromCookie()) { // 创建Session session = manager.createSession(getRequestedSessionId()); } else { session = manager.createSession(null); } // 创建一个新的Session Cookies if ((session != null) && (getContext() != null) && getContext().getCookies()) { Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, session.getIdInternal()); // 配置Session Cookie configureSessionCookie(cookie); // 在响应中加入Session Cookie response.addCookieInternal(cookie); } if (session != null) { // 更新访问时间 session.access(); return (session); } else { return (null); } }这个方法说明了Session创建的大致过程,首先判断requestedSessionId是否存在,如果存在,那么根据这个ID去查找 Session对象。如果requestedSessionId不存在或者没有取到Session,并且传递给#getSession(boolean) 的参数为真,那么要创建一个新的Session,并且给客户端写回去一个Session Cookie。
首先,我感兴趣的是requestedSessionId的赋值,它到底是什么时候被赋值的呢?
还要向回看Tomcat的请求处理过程,请求曾到过这一 步,org.apache.catalina.connector.CoyoteAdapter的#service()方法。里边有这样一句方法调 用:postParseRequest(req, request, res, response)。就是这一步处理了SessionID的获取,这个方法调用了#parseSessionId()和 parseSessionCookiesId()这两个方法,就是它对Session ID进行了提取,源代码分别如下:
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 // 在URL中提取Session ID 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)); 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); } // 设定Session ID来自于URL request.setRequestedSessionURL(true); } else { request.setRequestedSessionId(null); request.setRequestedSessionURL(false); } }
protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { Context context = (Context) request.getMappingData().context; if (context != null && !context.getCookies()) return; // 返回Cookie Cookies serverCookies = req.getCookies(); int count = serverCookies.getCookieCount(); if (count <= 0) return; for (int i = 0; i < count; i++) { ServerCookie scookie = serverCookies.getCookie(i); // 判断是否有JSESSIONID这个名字的Cookie if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) { // Override anything requested in the URL if (!request.isRequestedSessionIdFromCookie()) { // 设定Session ID convertMB(scookie.getValue()); request.setRequestedSessionId(scookie.getValue().toString()); // 如果之前在URL中读到了SessionID,那么会覆盖它 request.setRequestedSessionCookie(true); request.setRequestedSessionURL(false); if (log.isDebugEnabled()) log.debug(" Requested cookie session id is " + request.getRequestedSessionId()); } else { if (!request.isRequestedSessionIdValid()) { convertMB(scookie.getValue()); request.setRequestedSessionId(scookie.getValue().toString()); } } } } }Tomcat就是通过上边的两个方法读到URL或者Cookie中存放的Session ID的。
了解了Session ID的获取,下面要看一下Session的查找过程,就是org.apache.catalina.session.StandardManager的#findSession()方法。这个方法是在它的基类中定义的,源代码如下:
public Session findSession(String id) throws IOException { if (id == null) return (null); return (Session) sessions.get(id); }代码很短,其中sessions是一个ConcurrentHashMap<String, Session>对象。那么这个sessions的对象是什么时候载入的Session呢?
启动的时候!可以看一下StandardManager#start()方法。最后调用了#load()方法,这个就是载入Session的方法了:
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()方法来具体的载入Session,源代码如下:
protected void doLoad() throws ClassNotFoundException, IOException { if (log.isDebugEnabled()) log.debug("Start: Loading persisted sessions"); // 清空Map sessions.clear(); // 对应work/Catalina/localhost/%app name%/SESSIONS.ser文件 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 { // 载入Session缓存文件 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; } synchronized (sessions) { try { // 读出Session个数 Integer count = (Integer) ois.readObject(); int n = count.intValue(); if (log.isDebugEnabled()) log.debug("Loading " + n + " persisted sessions"); // 读入Session 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 { try { if (ois != null) ois.close(); } catch (IOException f) { } // 删除Session缓存文件 if (file != null && file.exists()) file.delete(); } } if (log.isDebugEnabled()) log.debug("Finish: Loading persisted sessions"); }大致知道了Session的读取过程,后面就是Session没找到时创建Session的过程了。具体就是org.apache.catalina.session.StandardManager的#createSession()方法:
public Session createSession(String sessionId) { if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) { rejectedSessions++; throw new IllegalStateException(sm.getString("standardManager.createSession.ise")); } return (super.createSession(sessionId)); }最后调用到了它的基类的#createSession()方法了。
public Session createSession(String sessionId) { // 创建一个新的Session Session session = createEmptySession(); // 初始化Session的属性 session.setNew(true); session.setValid(true); session.setCreationTime(System.currentTimeMillis()); session.setMaxInactiveInterval(this.maxInactiveInterval); // 如果Session ID为null,那么就生成一个 if (sessionId == null) { sessionId = generateSessionId(); } session.setId(sessionId); sessionCounter++; return (session); }
通过上述过程,一个新的Session就创建出来了。
后台处理
Tomcat会开启一个后台线程每隔一段时间检查Session的有效性,这个线程是在Tomcat启动的时候当StardardEngine启动时随之启动的。可以参看StardardEngine的基类ContainerBase的#threadStart()方法:
protected void threadStart() { if (thread != null) return; if (backgroundProcessorDelay <= 0) return; threadDone = false; String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; // 开启后台的监控线程 thread = new Thread(new ContainerBackgroundProcessor(), threadName); thread.setDaemon(true); thread.start(); }这个方法启动了一个ContainerBackgroundProcessor类的线程,这个类重写的#run()方法中包括了对Session 的有效性监控。具体的细节就不详细陈述了。每隔一段时间,此线程就会启动一次并调用了ManageBase的#backgroundProcess()方 法。其源代码如下:
public void backgroundProcess() { count = (count + 1) % processExpiresFrequency; if (count == 0) processExpires(); }每隔一段时间就会调用processExpires()方法去判断Session的有效性。
public void processExpires() { // 现在的时间 long timeNow = System.currentTimeMillis(); // 所有的Session对象 Session sessions[] = findSessions(); int expireHere = 0; if (log.isDebugEnabled()) log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); for (int i = 0; i < sessions.length; i++) { // 判断并设定Session是否失效 if (sessions[i] != null && !sessions[i].isValid()) { expireHere++; } } long timeEnd = System.currentTimeMillis(); if (log.isDebugEnabled()) log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); processingTime += (timeEnd - timeNow); }此方法最终调用了isValid()去判断和设定Session是否失效,源代码如下所示:
public boolean isValid() { // 是否过期 if (this.expiring) { return true; } // 是否有效 if (!this.isValid) { return false; } // 正在使用中并且访问数大于0 if (ACTIVITY_CHECK && accessCount.get() > 0) { return true; } if (maxInactiveInterval >= 0) { // 判断Session是否过期 long timeNow = System.currentTimeMillis(); int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L); if (timeIdle >= maxInactiveInterval) { // 设定Session过期 expire(true); } } return (this.isValid); }
发表评论
-
tomcat cluster 源码分析
2012-03-01 18:16 2765看完tomcat的源码,迫不及待的想研究下tomcat集群,可 ... -
tomcat中的线程
2012-02-21 15:14 4207tomcat启动过程中会启动许多线程 这里总结下: ... -
学习HTTP Status Code的一些总结
2012-02-09 11:07 2255这几天学习了一下 ... -
Tomcat的WebappClassLoader(web应用类加载器)详解
2012-02-05 16:44 1988转载自: http://bl ... -
tomcat 源码解析
2011-12-31 15:45 1646tomcat 首先启动 1. 启动的时候对配置文件进行解析。 ... -
tomcat源码安装并调试
2011-12-29 12:35 1906闲来无事,做B/S开发,tomcat天天用,但是对于其原理以及 ... -
eclipse tomcat 配置
2011-09-15 16:10 1940Configure Tomcat's Paths The ... -
META-INF/context.xml文件说明
2011-09-14 11:29 10685crossContext 如果想在应用内调用ServletC ... -
Linux部署tomcat
2011-04-07 09:19 2505今天,同事的服务器上部署一个新的tomcat,但他的服 ...
相关推荐
标题中的"tomcat-redis-session-manager-1.2-tomcat-7-java-7"表明这是一个针对Tomcat服务器,用于管理session的组件,版本为1.2,适配Tomcat 7和Java 7环境。这个组件的主要作用是将Tomcat的会话管理功能与Redis...
为了实现session共享,我们需要在每个Tomcat的server.xml配置文件中,配置Session ID的Cookie路径为"/",并启用`<Manager>`标签的`驮sessionCacheName`属性,以便与Memcached进行交互。 3. **Memcached**:...
Memcached-Session-Manager是为Tomcat提供集群环境下的Session共享管理功能。MSM借助Memcached这一分布式内存对象缓存系统来存储和管理session,让多个Tomcat实例能够共享用户的会话信息。这样,即使用户的请求在多...
4. **处理Session**:在应用程序中,继续像平常一样创建和使用Session,Tomcat-redis-session-manager会在后台透明地处理Session的存储和检索。 5. **监控与优化**:为了确保系统的稳定运行,还需要监控Redis的性能...
- **Session管理**:Tomcat默认的Session管理机制在集群环境中可能导致Session丢失,因此需要结合Memcache实现Session共享。 3. **Memcache**: - **Session共享**:Memcache是一个高性能的分布式内存对象缓存...
- **设置管理界面用户**:在`tomcat-users.xml`文件中添加角色和用户,以允许访问Tomcat的管理后台。例如,添加一个名为“manager”的角色和用户名/密码均为“tomcat”的用户。 6. **Tomcat管理后台** - 管理后台...
通过这些API,开发者可以创建、配置和管理Web应用程序,实现动态网页服务和后台处理。 二、Servlet编程 Servlet是Java Web开发的核心,Tomcat支持Servlet 3.0规范。通过`javax.servlet`包中的接口和类,开发者可以...
3. **StandardSession**:它是HttpSession的实现,同时也是Session接口的实现,负责Tomcat内部的会话管理,包括存储和生命周期管理。 4. **StandardSessionFacade**:这是一个门面类,它包裹了一个StandardSession...
### Keepalived+nginx+tomcat+redis_session_share #### 环境配置与实现原理 本案例通过搭建一个基于`Keepalived`、`nginx`、`Tomcat`及`Redis`的服务集群来实现应用服务的高可用性和负载均衡,并通过`Redis`实现...
2. 使用 Nginx 负载均衡的 ip_hash 策略:可以使用 Nginx 负载均衡的 ip_hash 策略实现用户每次访问都绑定到同一台具体的后台 tomcat 服务器实现 session 总是存在。 3. 自己写一套 Session 会话管理的工具类:可以...
现在Ajax在Web项目中应用广泛,几乎可以说无处不在,这就带来另外一个问题:当Ajax请求遇到Session超时,应该怎么办? 显而易见,传统的页面跳转在此已经不适用,因为Ajax请求是XMLHTTPRequest对象发起的而不
8. **Session/Cookie管理**:用于跟踪用户购物车状态和登录信息。 9. **安全性**:可能涉及到HTTPS、CSRF令牌、XSS防护等安全措施。 10. **Tomcat服务器**:作为Java Web应用的部署环境。 11. **版本控制**:如Git,...
【超市管理系统后台模板】是一个专为JSP初学者设计的项目模板,旨在提供一个基础的、易于理解的超市管理系统的后台界面。这个模板包含了实现超市日常运营所需的基本功能,如商品管理、库存控制、销售记录以及用户...
1. **添加依赖**:首先,需要在项目的依赖管理中引入`msm-kryo-serializer`包,确保所有Tomcat实例都可以使用这个库进行session序列化。 2. **配置session共享**:在每个Tomcat的`conf/context.xml`文件中,定义一...
在本场景中,Nginx作为负载均衡器,可以根据预设策略(如轮询、最少连接、IP哈希等)将来自客户端的请求分发到后台的多个Tomcat实例上,有效分散压力,提高系统整体的处理能力。同时,Nginx还可以作为静态资源服务器...
- **集群**:如果需要高可用性和负载均衡,可以设置Tomcat集群,实现多个实例间的 session 共享。 - **SSL配置**:为了保证数据传输的安全性,可以配置Tomcat支持HTTPS。 在实际开发和生产环境中,了解并熟练掌握...
新闻管理系统是基于Java Web技术,利用JSP(JavaServer Pages)作为表现层,Tomcat作为应用服务器,MySQL作为后台数据库构建的一款实用软件。它主要用于发布、管理和维护各类新闻信息,适用于学校、企业或其他组织...
后台与mysql数据库进行连接,dao-service-action都是一一对应,便于理解。此后台管理系统,一共有三个表,用户注册表,部门表以及员工表。主要功能有用户的登录与注册,部门的增查,员工的增删改查。还采用了session...
- **Session Management**:改进了会话管理,支持跨应用的会话跟踪,以及更灵活的会话超时设置。 - **Multipart解析**:支持了多部分表单数据的解析,使得上传文件变得更加简单。 2. **JSP 2.0规范**: - **EL...
在这个系统中,`jsp`(JavaServer Pages)负责展示动态内容,`tomcat`作为应用服务器处理请求并执行Java代码,而`MysqL`则作为后台数据库存储和管理新闻数据。 1. **jsp**:JSP是一种基于Java的动态网页技术,它...