`
chainhou
  • 浏览: 174892 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Tomcat中的session是如何管理的?

阅读更多
最近有个朋友问我:
引用
tomcat的session存在哪里?

答:内存中。又问:
引用
那既然都保存在内存中,要清除过期的sesion时,又怎么能区分是哪个应用的session而不会清除错误?

答:(当时没看过这块的代码),说由于每个应用对应一个Session管理,此处应该有类似于数组之类的东西,将该应用的session管理起来,当该应用移除或者某些sesion过期时可以准确的删除掉。最近看了下代码,对比下源码,发现回复的还行,没有特别大的出入。

我们的应用中一般都会用到session,那这个session在应用服务器内部到底是怎么保存到处理的呢?

当我们请求一个应用时,如果页面中用到了session,此时的创建session的调用链如下:

Daemon Thread [http-bio-8090-exec-1] (Suspended (breakpoint at line 145 in SessionIdGenerator))	
	owns: SocketWrapper<E>  (id=234)	
	SessionIdGenerator.generateSessionId() line: 145	
	StandardManager(ManagerBase).generateSessionId() line: 807	
	StandardManager(ManagerBase).createSession(String) line: 653	
	Request.doGetSession(boolean) line: 2892	
	Request.getSession(boolean) line: 2315	
	RequestFacade.getSession(boolean) line: 898	
	RequestFacade.getSession() line: 910	
	PageContextImpl._initialize(Servlet, ServletRequest, ServletResponse, String, boolean, int, boolean) line: 146	
	PageContextImpl.initialize(Servlet, ServletRequest, ServletResponse, String, boolean, int, boolean) line: 125	
	JspFactoryImpl.internalGetPageContext(Servlet, ServletRequest, ServletResponse, String, boolean, int, boolean) line: 112	
	JspFactoryImpl.getPageContext(Servlet, ServletRequest, ServletResponse, String, boolean, int, boolean) line: 65	
	index.jsp line: not available	
	index_jsp(HttpJspBase).service(HttpServletRequest, HttpServletResponse) line: 70	
	index_jsp(HttpServlet).service(ServletRequest, ServletResponse) line: 728	
	JspServletWrapper.service(HttpServletRequest, HttpServletResponse, boolean) line: 432	
	JspServlet.serviceJspFile(HttpServletRequest, HttpServletResponse, String, boolean) line: 390	
	JspServlet.service(HttpServletRequest, HttpServletResponse) line: 334	
	JspServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 728	
	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 305	
	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
	StandardWrapperValve.invoke(Request, Response) line: 222	
	StandardContextValve.invoke(Request, Response) line: 123	
	NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 472	
	StandardHostValve.invoke(Request, Response) line: 171	
	ErrorReportValve.invoke(Request, Response) line: 99	
	AccessLogValve.invoke(Request, Response) line: 936	
	StandardEngineValve.invoke(Request, Response) line: 118	
	CoyoteAdapter.service(Request, Response) line: 408	
	Http11Processor(AbstractHttp11Processor<S>).process(SocketWrapper<S>) line: 1009	
	Http11Protocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler<S,P>).process(SocketWrapper<S>, SocketStatus) line: 589	
	JIoEndpoint$SocketProcessor.run() line: 310	
	ThreadPoolExecutor$Worker.runTask(Runnable) line: 895	
	ThreadPoolExecutor$Worker.run() line: 918	
	TaskThread(Thread).run() line: 662


以上调用链的部分关键代码:

	
	 /**
     * Construct and return a new session object, based on the default
     * settings specified by this Manager's properties.  The session
     * id specified will be used as the session id.  
     * If a new session cannot be created for any reason, return 
     * <code>null</code>.
     * 
     * @param sessionId The session id which should be used to create the
     *  new session; if <code>null</code>, a new session id will be
     *  generated
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     */
    @Override
    public Session createSession(String sessionId) {
        
        if ((maxActiveSessions >= 0) &&
                (getActiveSessions() >= maxActiveSessions)) {
            rejectedSessions++;
            throw new TooManyActiveSessionsException(
                    sm.getString("managerBase.createSession.ise"),
                    maxActiveSessions);
        }
        
        // 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);
        String id = sessionId;
        if (id == null) {
            id = generateSessionId();  //此处生成sessionID
        }
        session.setId(id);
        sessionCounter++;

        SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
        synchronized (sessionCreationTiming) {
            sessionCreationTiming.add(timing);
            sessionCreationTiming.poll();
        }
        return (session);

    }
	
	
	
	    public void setId(String id, boolean notify) {

        if ((this.id != null) && (manager != null))
            manager.remove(this);

        this.id = id;

        if (manager != null)
            manager.add(this); //注意此处

        if (notify) {
            tellNew();
        }
    }


在setId时,同时在Manager中将相应的session保存了下来。此处对于session的保存使用的是ConcurrentHashMap,在创建后将其添加到map中,session过期后将其移除。


    /**
     * Add this Session to the set of active Sessions for this Manager.
     *
     * @param session Session to be added
     */
    @Override
    public void add(Session session) {

        sessions.put(session.getIdInternal(), session);
        int size = getActiveSessions();  //此处应该可以使用AtomicInteger替换掉。
        if( size > maxActive ) {
            synchronized(maxActiveUpdateLock) {
                if( size > maxActive ) {
                    maxActive = size;
                }
            }
        }
    }	




而在停止一个应用时,相应的remove session的调用链如下:
	Daemon Thread [http-bio-8090-exec-2] (Suspended (breakpoint at line 733 in ManagerBase))	
	owns: StandardSession  (id=340)	
	owns: StandardManager  (id=326)	
	owns: StandardContext  (id=327)	
	owns: SocketWrapper<E>  (id=341)	
	StandardManager(ManagerBase).remove(Session, boolean) line: 733	
	StandardSession.expire(boolean) line: 840	
	StandardManager.doUnload() line: 463	
	StandardManager.unload() line: 353	
	StandardManager.stopInternal() line: 518	
	StandardManager(LifecycleBase).stop() line: 232	
	StandardContext.stopInternal() line: 5569	
	StandardContext(LifecycleBase).stop() line: 232	
	HTMLManagerServlet(ManagerServlet).stop(PrintWriter, ContextName, StringManager) line: 1306	
	HTMLManagerServlet.stop(ContextName, StringManager) line: 733	
	HTMLManagerServlet.doPost(HttpServletRequest, HttpServletResponse) line: 221	
	HTMLManagerServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 647	
	HTMLManagerServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 728	
	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 305	
	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
	CsrfPreventionFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 213	
	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
	SetCharacterEncodingFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 108	
	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
	StandardWrapperValve.invoke(Request, Response) line: 222	
	StandardContextValve.invoke(Request, Response) line: 123	
	BasicAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 581	
	StandardHostValve.invoke(Request, Response) line: 171	
	ErrorReportValve.invoke(Request, Response) line: 99	
	AccessLogValve.invoke(Request, Response) line: 936	
	StandardEngineValve.invoke(Request, Response) line: 118	
	CoyoteAdapter.service(Request, Response) line: 408	
	Http11Processor(AbstractHttp11Processor<S>).process(SocketWrapper<S>) line: 1009	
	Http11Protocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler<S,P>).process(SocketWrapper<S>, SocketStatus) line: 589	
	JIoEndpoint$SocketProcessor.run() line: 310	
	ThreadPoolExecutor$Worker.runTask(Runnable) line: 895	
	ThreadPoolExecutor$Worker.run() line: 918	
	TaskThread(Thread).run() line: 662	



其中执行remove的代码如下:
	 /**
     * Perform the internal processing required to invalidate this session,
     * without triggering an exception if the session has already expired.
     *
     * @param notify Should we notify listeners about the demise of
     *  this session?
     */
    public void expire(boolean notify) {

        // Check to see if expire is in progress or has previously been called
        if (expiring || !isValid)
            return;

        synchronized (this) {
            // Check again, now we are inside the sync so this code only runs once
            // Double check locking - expiring and isValid need to be volatile
            if (expiring || !isValid)
                return;

            if (manager == null)
                return;
			... //省略部分代码
		}
		... //省略部分代码
			   if (ACTIVITY_CHECK) {
                accessCount.set(0);
            }
            setValid(false);

            // Remove this session from our manager's active sessions
            manager.remove(this, true);
	}

StandardManager中的remove方法:
    /**
     * Remove this Session from the active Sessions for this Manager.
     *
     * @param session   Session to be removed
     * @param update    Should the expiration statistics be updated
     */
    @Override
    public void remove(Session session, boolean update) {
        
        // If the session has expired - as opposed to just being removed from
        // the manager because it is being persisted - update the expired stats
        if (update) {
            long timeNow = System.currentTimeMillis();
            int timeAlive =
                (int) (timeNow - session.getCreationTimeInternal())/1000;
            updateSessionMaxAliveTime(timeAlive);
            expiredSessions.incrementAndGet();
            SessionTiming timing = new SessionTiming(timeNow, timeAlive);
            synchronized (sessionExpirationTiming) {
                sessionExpirationTiming.add(timing);
                sessionExpirationTiming.poll();
            }
        }

        if (session.getIdInternal() != null) {
            sessions.remove(session.getIdInternal());  //注意此处,即为上面保存session的concurrentHashMap
        }
    }

分享到:
评论

相关推荐

    设定tomcat中session过期时间.txt

    在Web开发中,Session管理是确保用户状态跟踪的重要机制之一。Tomcat作为一款广泛使用的Java应用服务器及Servlet容器,提供了多种方式来设定Session的有效时长。这有助于开发者根据具体业务需求灵活调整Session的...

    tomcat redis session.rar

    综上所述,"Tomcat Redis Session"是一种在分布式环境中保证用户会话一致性的解决方案,通过集成Redis和Nginx,有效地解决了Web应用集群中的Session管理难题。在实际部署中,还需要考虑系统整体架构、性能优化和运维...

    tomcat-redis-session管理 使用说明

    【标题】:“Tomcat-Redis-Session管理”的实践指南 在Web应用开发中,Session管理是关键的一环,用于在用户浏览器与服务器之间保持状态。传统的Session存储方式是将数据存放在服务器内存中,但随着高并发访问和...

    Tomcat_Session的持久化

    Tomcat_Session 的持久...Tomcat 提供了 StandardManager 和 PersistentManager 两个实现类来管理 Session,其中 PersistentManager 能够把 Session 对象保存到 Session Store 中,提供了更为灵活的 Session 管理功能。

    Tomcat memcached Session依赖jar包

    在Tomcat中集成memcached作为Session管理器,可以将Session数据分布在网络中的多个节点上,实现Session复制和高可用性。 为了在Tomcat中使用memcached进行Session管理,你需要以下关键的依赖jar包: 1. **...

    tomcat实现session共享

    在`Tomcat`中,我们可以通过`Tomcat Redis Session Manager`来实现与Redis的集成。这个组件允许我们将Tomcat的session数据存储在Redis中,使得所有服务器都能访问到这些数据。在提供的压缩包文件中,`jedis-2.1.0....

    tomcat8+memcached session共享

    7. `memcached-session-manager-tc8-1.8.3.jar`:这个是针对Tomcat 8版本的session管理器实现,确保与Tomcat 8的兼容性。 8. `minlog-1.2.jar`:这是一个简单的日志库,可能用于在处理session共享时记录和调试信息。...

    tomcat8专用session管理包.rar

    标题中的“tomcat8专用session管理包.rar”指的是一个针对Tomcat 8的特定session管理解决方案,这个压缩包包含了在使用Nginx作为反向代理服务器,并与Redis结合实现负载均衡场景下,确保Tomcat应用间session数据共享...

    tomcat-session共享

    Tomcat中的Session管理** 在单台Tomcat服务器上,Session信息默认存储在服务器的内存中。然而,当部署多个Tomcat实例时,由于每个实例都有自己的Session存储,导致Session无法跨实例共享,用户在切换服务器时可能会...

    tomcat集群session共享

    综上所述,实现Tomcat集群session共享主要涉及Tomcat的session管理机制、Redis的集成以及相应的配置和优化。通过合理配置,可以确保在高并发环境下提供无缝的用户体验,同时提升系统的可扩展性和可靠性。

    Tomcat8(Tomcat9)+redis实现Session共享(支持Redis集群)

    Tomcat作为最常用的Java Servlet容器,其Session管理能力直接影响到应用的性能和可扩展性。本教程将详细介绍如何利用Tomcat 8或9以及Redis实现Session共享,支持Redis集群,以提高系统的可伸缩性和数据一致性。 ...

    tomcat5 session 复制

    `SimpleTcpCluster` 是一个基于 TCP 的集群实现,而 `DeltaManager` 是用于处理 Session 数据更新的管理器。主要配置包括: - `tcpListenAddress`:指定接收复制数据的 IP 地址,例如 `192.168.1.55`。 - `...

    tomcat-redis-session-manager包集合下载(tomcat8)

    综上所述,"tomcat-redis-session-manager包集合"为使用Tomcat8和JDK1.8的开发者提供了便捷的手段,通过集成Redis来增强session管理,提升应用在分布式环境下的性能和可靠性。正确配置和使用这个工具可以显著改善...

    redis+tomcat实现session的jar

    5. **示例代码**:可能包含如何在Tomcat的web.xml配置文件中添加和配置这个session管理器的示例。 集成这个模块到Tomcat中,开发者需要: 1. 将jar文件放入Tomcat的lib目录,使服务器能加载到这个组件。 2. 在web....

    redis tomcat7 session共享

    2. **安装Redis-Session-Manager**: 在`Tomcat7`中,我们需要一个能够与Redis通信的Session管理器。可以通过`Spring Session`或者`JedisSessionRepositoryFilter`来实现。这里以`JedisSessionRepositoryFilter`为例...

    tomcat集群session共享解决方案

    6. **Cookie管理**:可以将session ID存储在cookie中,通过负载均衡器将请求路由到拥有相应session的服务器。这种方法简化了session的处理,但可能面临cookie篡改或跨站请求伪造(CSRF)攻击的风险。 在实际应用中...

    session 共享 tomcat-redis-session-manager 所需要的jar (绝对可用)

    总结来说,这个压缩包提供了一套完整的解决方案,包括了连接Redis的Jedis客户端、对象池管理、Tomcat的Session管理器以及配置文件,使得开发者可以轻松地在Tomcat集群中实现Session共享,提升系统的可扩展性和容错性...

    tomcat-redis-session-manager

    总的来说,`tomcat-redis-session-manager`是应对分布式系统中session管理挑战的有效工具。它将Redis的强大功能引入Tomcat,实现了跨服务器的session共享,提高了应用的可扩展性和可靠性。正确配置和使用这个组件,...

    tomcat-redis-session-manager的jar包-包含Tomcat7和Tomcat8

    在现代Web应用程序开发中,session管理是一个至关重要的环节,它涉及到用户会话的持久化和跨请求的数据共享。传统的session管理方式在高并发、分布式环境中可能会面临效率低下和数据一致性的问题。为了解决这些问题...

    nginx+tomcat shiro实现多tomcat下session共享

    在多Tomcat环境下的session共享中,Shiro可以作为会话管理的工具,它支持自定义的session管理策略。 4. **共享Session的解决方案**: 为了实现session共享,我们可以利用Redis这样的内存数据存储系统。Redis具有...

Global site tag (gtag.js) - Google Analytics