`
charyle
  • 浏览: 165842 次
  • 性别: Icon_minigender_1
  • 来自: 天蝎座
社区版块
存档分类
最新评论

Tomcat源码之Session实现

 
阅读更多

     前段时间看了阵子Tomcat的源码,有所得。早想总结出来可惜太多了,不知道从何说起,今天早上有时间先从Session如何实现的说起吧,免得时间越久忘记的越多。

     Tomcat的容器有四个级别,分别为Engine、Host、Context和Wrapper。所有的容器都有相同的父类,即org.apache.catalina.core.ContainerBase。那么session的管理在哪个级别的,Engine、Host还是Context?答案是在Context级别实现的,即每个应用有自己的session管理对象。

      StandardContext是Context容器(即你的应用)的标准实现,在其start方法中(即启动时候)将创建该应用的session管理对象,非集群的情况下Session管理对象类为org.apache.catalina.session.StandardManager,它是session的标准管理器,每个Context(应用)关联一个,它实现了session的创建、查询、过期检测和序列化和反序列化,序列化和反序列化是在容器重启过程中用到的,保证重启不会丢失活动的session。

      StandardContext的父类是org.apache.catalina.session.ManagerBase,其session的保存变量声明为protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();即利用ConcurrentHashMap保存session,如果想所有的应用共用一个session可以先将此变量设置为static的,然后修改设置cookie的JSESSION的path为“/”。

      Session的创建——当request.getSession时候,根据请求中cookie中的或者url后的JSESSION参数查找session,如果存在则返回相应的session,不存在则创建并在响应(response)设置头信息,要求设置客户端cookie的JSESSION为session的id,path为应用的路径。

      Session的过期检测——session的超时检测如何实现的呢?

      在ContainerBase中有个ContainerBackgroundProcessor类。该类如下:

     

 protected class ContainerBackgroundProcessor implements Runnable {

        public void run() {
            while (!threadDone) {
                try {
                    Thread.sleep(backgroundProcessorDelay * 1000L);
                } catch (InterruptedException e) {
                    ;
                }
                if (!threadDone) {
                    Container parent = (Container) getMappingObject();
                    ClassLoader cl = 
                        Thread.currentThread().getContextClassLoader();
                    if (parent.getLoader() != null) {
                        cl = parent.getLoader().getClassLoader();
                    }
                    processChildren(parent, cl);
                }
            }
        }

        protected void processChildren(Container container, ClassLoader cl) {
            try {
                if (container.getLoader() != null) {
                    Thread.currentThread().setContextClassLoader
                        (container.getLoader().getClassLoader());
                }
                container.backgroundProcess();
            } catch (Throwable t) {
                log.error("Exception invoking periodic operation: ", t);
            } finally {
                Thread.currentThread().setContextClassLoader(cl);
            }
            Container[] children = container.findChildren();
            for (int i = 0; i < children.length; i++) {
                if (children[i].getBackgroundProcessorDelay() <= 0) {
                    processChildren(children[i], cl);
                }
            }
        }

    }

 

 

      当容器启动中会创建此类并运行,该类为多线程实现,即相当于启动一个与该容器相关的后台运行的线程。这个run方法中递归调用容器的processChildren方法,该方法首先运行容器相关的backgroundProcess方法,然后再递归调用子容器的processChildren,在backgroundProcess方法中会启动可能与容器相关的各种后台程序。其代码如下:

      

public void backgroundProcess() {
        
        if (!started)
            return;

        if (cluster != null) {
            try {
                cluster.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);                
            }
        }
        if (loader != null) {
            try {
                loader.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                
            }
        }
        if (manager != null) {
            try {
                manager.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);                
            }
        }
        if (realm != null) {
            try {
                realm.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);                
            }
        }
        Valve current = pipeline.getFirst();
        while (current != null) {
            try {
                current.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);                
            }
            current = current.getNext();
        }
        lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
    }

 

 

      其中如果为Context容器则会启动manager,此manager即为StandardManager,在其父类ManagerBase中的backgroundProcess方法如下:

     

/**
     * Implements the Manager interface, direct call to processExpires
     */
    public void backgroundProcess() {
        count = (count + 1) % processExpiresFrequency;
        if (count == 0)
            processExpires();
    }

 

      processExpiresFrequency默认为6,相当于每过6秒检测一次,检测方法主要调用session的isValid方法,该方法判断当前时间与最近访问时间间隔是否超过设定的时间间隔。

      另外,每次访问应用,都会调用StandardSession的access方法,即更新最近访问时间。

      要工作了,最后还有session的监听的实现,  注册监听是在应用的web.xml中声明的,那么相应的监听也是保存在Context容器的变量中,其getApplicationLifecycleListeners()方法获得容器的监听数组,其声明为:

 

    

private transient Object applicationLifecycleListenersObjects[] = 
        new Object[0];

  在StandardSession的expire方法如下:

 

Object listeners[] = context.getApplicationLifecycleListeners();
                if (notify && (listeners != null)) {
                    HttpSessionEvent event =
                        new HttpSessionEvent(getSession());
                    for (int i = 0; i < listeners.length; i++) {
                        int j = (listeners.length - 1) - i;
                        if (!(listeners[j] instanceof HttpSessionListener))
                            continue;
                        HttpSessionListener listener =
                            (HttpSessionListener) listeners[j];
                        try {
                            fireContainerEvent(context,
                                               "beforeSessionDestroyed",
                                               listener);
                            listener.sessionDestroyed(event);
                            fireContainerEvent(context,
                                               "afterSessionDestroyed",
                                               listener);
                        } catch (Throwable t) {
                            try {
                                fireContainerEvent(context,
                                                   "afterSessionDestroyed",
                                                   listener);
                            } catch (Exception e) {
                                // Ignore
                            }
                            manager.getContainer().getLogger().error
                                (sm.getString("standardSession.sessionEvent"), t);
                        }
                    }
                }

    如果监听为对Session的监听,则触发监听,而在创建session的设置session的id方法中会调用tellNew(),其会触发session创建时session监听程序。

    就这么多吧,要上班了。。。

 

分享到:
评论

相关推荐

    tomcat源码

    Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...

    tomcat redis session.rar

    【标题】:“Tomcat Redis Session”指的是在Tomcat集群环境中,通过Redis来实现Session的共享与同步,以解决集群中的Session一致性问题。 【描述】:“Tomcat集群Nginx使用Redis保证Session同步”这一场景中,通常...

    tomcat-redis-session-manager源码

    本文将深度剖析`Tomcat-Redis-Session-Manager`的源码,揭示其如何实现Tomcat与Redis之间的会话同步。 首先,我们来看`Tomcat-Redis-Session-Manager`的核心功能:它将Tomcat默认的内存会话管理替换为基于Redis的...

    Nginx+Tomcat+Memcached实现tomcat集群和session共享

    下面我们将详细探讨如何实现Nginx+Tomcat+Memcached的集群和Session共享。 **Nginx** Nginx是一款轻量级的Web服务器/反向代理服务器,以其高效的性能和低内存占用著称。在本场景中,Nginx主要负责以下任务: 1. **...

    Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享

    本篇文章将探讨如何利用Redis、Tomcat和Nginx来实现Session共享,以便在分布式环境中保持用户状态的一致性。 首先,让我们了解一下Session的概念。Session是Web服务器用来跟踪用户状态的一种机制。当用户登录后,...

    Tomcat8亲测可用 tomcat-redis-session-manager的jar包

    这个组件实现了将Tomcat应用服务器中的用户session数据存储到Redis分布式缓存系统中,以提高系统的可伸缩性和性能。Redis是一个高性能的键值数据库,常被用来作为缓存服务,因其速度快、数据持久化等特点,非常适合...

    tomcat8集群与redis实现session共享所需Jar包

    2. **准备Jar包**: 压缩包文件"tomcat8-redis-session-manager"包含实现Tomcat8与Redis交互所需的库,如`jedis.jar`(用于Java操作Redis)和可能的session管理器实现,如`tomcat-redis-session-manager.jar`。...

    tomcat7源码

    此外,源码中还有许多值得关注的部分,如会话管理(SessionManager)、监听器(Listener)的注册、错误处理(ErrorReportValve)、部署工具(Deployer)等。理解这些组件的工作原理,将有助于我们在实际开发中遇到...

    redis-tomcat7-session共享配置文档及依赖包

    本文将详细讲解如何通过Redis实现Tomcat7的session共享,并介绍相关配置和依赖包。首先,我们来看一下核心的组件:Redis、Tomcat7以及session管理。 Redis是一个开源的、基于内存的数据结构存储系统,它可以作为...

    tomcat8源码

    Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,...因此,对Tomcat源码的学习对于Java Web开发者来说是至关重要的。

    分布式集群Session共享 简单多tomcat8+redis的session共享实现

    源码可以帮助我们深入了解Session共享的具体实现,包括如何序列化和反序列化Session对象,如何处理并发访问,以及如何在Redis中设置和获取Session数据等。通过阅读源码,开发者可以学习到如何自定义Session管理器,...

    tomcat8集群redis实现session共享jar包

    这些jar包通常包括Tomcat的Redis Session Manager实现以及Redis客户端库(如Jedis)。将这些jar包添加到Tomcat的`lib`目录下,使得Tomcat在启动时能够加载它们。 4. **配置Redis Session Manager**:除了在`server....

    tomcat-redis-session-manager-master.zip

    本文将围绕“tomcat-redis-session-manager-master.zip”这个压缩包中的源码,深入探讨如何使用Redis实现Tomcat的session共享,并提供详尽的知识点解析。 首先,我们要理解Tomcat的session管理基础。在默认情况下,...

    redis+tomcat实现session的jar

    标题中的"redis+tomcat实现session的jar"指的是在Tomcat服务器中利用Redis数据库来实现Web应用程序的会话(session)共享技术。Redis是一个高性能的键值存储系统,常用于缓存和分布式环境下的数据共享。在传统的Web...

    resis实现tomcat7 session 共享

    【标题】"resis实现tomcat7 session 共享"主要涉及的是在分布式环境中如何实现Tomcat服务器间的Session共享问题。Resin(ReStructured Servlet & JSP Engine)是一款轻量级、高性能的Java应用服务器,它支持Servlet...

    tomcat源码,servlet-api源码

    《深入理解Tomcat源码与Servlet-API》 Tomcat,作为Apache软件基金会的顶级项目,是Java Servlet和JavaServer Pages(JSP)的开源Web应用服务器,被广泛应用于中小型企业的Web服务部署。7.0.59版本是Tomcat的一个...

    tomcat8、8.5、9与redis实现session共享

    很好用,使用也很简单,把其中的三个Jar包拷贝到你的tomcat中的...tomcat8、8.5、9与redis实现session共享,并可以通过修改源码可自定义session键,访问地址:http://blog.csdn.net/fackyou200/article/details/78929008

    tomcat8.5.20-redis-session共享-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这个版本。注意...

    tomcat-redis配置session共享

    下面将详细介绍如何配置Tomcat与Redis来实现Session的共享。 首先,我们需要了解什么是Session。在Web开发中,Session是用于跟踪用户状态的一种技术。当用户登录后,服务器会为每个用户创建一个唯一的Session ID,...

    tomcat8-redis-session共享

    通过这种方式,Tomcat 8和Redis结合,能够实现高效的Session共享,确保用户在分布式环境中的会话一致性。注意,使用Redis存储Session时,需要注意数据的持久化策略以及Redis的内存管理,避免内存溢出。同时,考虑到...

Global site tag (gtag.js) - Google Analytics