`

Session管理

阅读更多

Tomcat中的session管理,首先的明白一点 : 不是你客户端一个请求传过去,服务器就会为创建一个会话,

不是的,如果后台没有对应的session操作,就是你的servlet中没有session操作(getSession(boolean)),那么就不会给你创建会话;

 

在开发JEE应用中,通常我们都是对会话进行处理,而对于会话的创建,维护,删除,则是服务器替我们完成!

而在Tomcat中,与会话有关的两个重要的类 : StandardSession , StandardManager(这个manager就像一个组件一样,在tomcat启动的时候就会start) ;

而standardsession 则是实现了HttpSession ; session 只是一个简单的对象就像一个POJO,对session 进行的操作则是通过StandardManger 实现,它继承自

ManagerBase ;在ManagerBase中定义了成员变量:session池:

Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();

 

StandardSession中的属性:

  

/**
     * The collection of user data attributes associated with this Session.
     */
 protected Map attributes = new ConcurrentHashMap();

/**
     * The time this session was created, in milliseconds since midnight,
     * January 1, 1970 GMT.
     */
    protected long creationTime = 0L;

/**
     * The last accessed time for this Session.
     */
    protected volatile long lastAccessedTime = creationTime;


    /**
     * The session event listeners for this Session.
     */
    protected transient ArrayList listeners = new ArrayList();


    /**
     * The Manager with which this Session is associated.
     */
    protected transient Manager manager = null;

    * The maximum time interval, in seconds, between client requests before
     * the servlet container may invalidate this session.  A negative time
     * indicates that the session should never time out.
     */
    protected int maxInactiveInterval = -1;


    /**
     * Flag indicating whether this session is new or not.
     */
    protected boolean isNew = false;


    /**
     * Flag indicating whether this session is valid or not.
     */
    protected volatile boolean isValid = false;

    
    /**
     * Internal notes associated with this session by Catalina components
     * and event listeners.  <b>IMPLEMENTATION NOTE:</b> This object is
     * <em>not</em> saved and restored across session serializations!
     */
    protected transient Map notes = new Hashtable();


    /**
     * The authenticated Principal associated with this session, if any.
     * <b>IMPLEMENTATION NOTE:</b>  This object is <i>not</i> saved and
     * restored across session serializations!
     */
    protected transient Principal principal = null;

    /**
     * The access count for this session.
     */
    protected transient AtomicInteger accessCount = null;

 

 

session的创建过程 :

   调用getSession(boolean create)   // 取得会话对象,如果没有session, create = true时 ,则会创建一个,create=false , 返回null

  

public HttpSession getSession(boolean create) {
        Session session = doGetSession(create);
        if (session != null) {
            return session.getSession();
        } else {
            return null;
        }
    }

 

doGetSession(create) :

  

protected Session doGetSession(boolean create) {  
  
        ……  
        // 先获取所在context的manager对象  
        Manager manager = null;  
        if (context != null)  
            manager = context.getManager();  
        if (manager == null)  
            return (null);      // Sessions are not supported  
          
        //这个requestedSessionId就是从Http request中解析出来的  
        if (requestedSessionId != null) {  // 如果之前存在session
            try {  
                //manager管理的session池中找相应的session对象  
                session = manager.findSession(requestedSessionId);  
            } catch (IOException e) {  
                session = null;  
            }  
            //判断session是否为空及是否过期超时  
            if ((session != null) && !session.isValid())  
                session = null;  
            if (session != null) {  
                //session对象有效,记录此次访问时间  
                session.access();  
                return (session);  
            }  
        }  
  
        // 如果参数是false,则不创建新session对象了,直接退出了  
        if (!create)  
            return (null);  
        if ((context != null) && (response != null) &&  
            context.getCookies() &&  
            response.getResponse().isCommitted()) {  
            throw new IllegalStateException  
              (sm.getString("coyoteRequest.sessionCreateCommitted"));  
        }  
  
        // 开始创建新session对象  
        if (connector.getEmptySessionPath()   
                && isRequestedSessionIdFromCookie()) {  
            session = manager.createSession(getRequestedSessionId());  // 调用manager中方法创建session
        } else {  
            session = manager.createSession(null);  
        }  
  
        // 将新session的jsessionid写入cookie,传给browser  
        if ((session != null) && (getContext() != null)  
               && getContext().getCookies()) {  
            Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,  
                                       session.getIdInternal());  
            configureSessionCookie(cookie);  
            response.addCookieInternal(cookie);  // response中的cookies就是在这里写入的
        }  
        //记录session最新访问时间  
        if (session != null) {  
            session.access();  
            return (session);  
        } else {  
            return (null);  
        }  
    }  

 接下来进入StandardManager的createSession方法:

  

public Session createSession(String sessionId) {  
//是个session数量控制逻辑,超过上限则抛异常退出  
    if ((maxActiveSessions >= 0) &&  
        (sessions.size() >= maxActiveSessions)) {  
        rejectedSessions++;  
        throw new IllegalStateException  
            (sm.getString("standardManager.createSession.ise"));  
    }  
    return (super.createSession(sessionId));  // 调用ManagerBase中的
}  

 

public Session createSession(String sessionId) {  
        // 创建一个新的StandardSession对象  
        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();  
        }
// 就是这里顺便把session加入session池中  
        session.setId(sessionId);  
        sessionCounter++;  
        return (session);  
    }  

    setId() 方法 :把session对象加入session池中!

    中间省略set(String id) ;

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); // 添加session到session池好隐蔽啊!!!
        
        if (notify) {
            tellNew();
        }
    }

 

   

generateSessionId() 生成sessionId:

   

protected synchronized String generateSessionId() {  
  
        byte random[] = new byte[16];  
        String jvmRoute = getJvmRoute();  
        String result = null;    
        // Render the result as a String of hexadecimal digits  
        StringBuffer buffer = new StringBuffer();  
        do {  
            int resultLenBytes = 0;  
            if (result != null) {  
                buffer = new StringBuffer();  
                duplicates++;  
            }    
            while (resultLenBytes < this.sessionIdLength) {  
                getRandomBytes(random);  
                random = getDigest().digest(random);  
                for (int j = 0;  
                j < random.length && resultLenBytes < this.sessionIdLength;  
                j++) {  
                    byte b1 = (byte) ((random[j] & 0xf0) >> 4);  
                    byte b2 = (byte) (random[j] & 0x0f);  
                    if (b1 < 10)  
                        buffer.append((char) ('0' + b1));  
                    else  
                        buffer.append((char) ('A' + (b1 - 10)));  
                    if (b2 < 10)  
                        buffer.append((char) ('0' + b2));  
                    else  
                        buffer.append((char) ('A' + (b2 - 10)));  
                    resultLenBytes++;  
                }  
            }  
            if (jvmRoute != null) {  
                buffer.append('.').append(jvmRoute);  
            }  
            result = buffer.toString();  
        //注意这个do…while结构  
        } while (sessions.containsKey(result));  // sessions就是那个session池,concurrentHashMap , 检查池中是否包含该key
        return (result);  
    }  

 到此 一个session对象就创建了!

 

   Session注销:

 

    主动注销

     调用sesion的servlet接口方法:

 

session.invalidate();

  // StanardSession中的invalidate()

public void invalidate() {  
        if (!isValidInternal())  
            throw new IllegalStateException  
                (sm.getString("standardSession.invalidate.ise"));  
        // 明显的注销方法  
        expire();  // expire 终止
    }  

 

     超时注销

     我们可以在web.xml中配置session的超时时间,也就是过了这个时间点,session就失效了,

     如果要你来设计,你会怎么做,每一个会话接入时,就会去扫描map一次,找到那些超时的,然后剔除吗! 

     这样,效率是不是降低了!

     那么,就是当你用这个会话的时候,再把它取出来,然后比较它是否过期,如果过期了,那么就重新创建一个会话!

     tomcat就是这么处理超时的!

     看源码 :

    

public boolean isValid() {  
        ……  
        //这就是判断距离上次访问是否超时的过程  
        if (maxInactiveInterval >= 0) {   
            long timeNow = System.currentTimeMillis();  
            int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);  
            if (timeIdle >= maxInactiveInterval) {  
                expire(true);  
            }  
        }  
        return (this.isValid);  
    }  

   expire() 方法:

  

public void expire(boolean notify) {   
  
        synchronized (this) {  
            ......  
            //设立标志位  
            setValid(false);  
  
            //计算一些统计值,例如此manager下所有session平均存活时间等  
            long timeNow = System.currentTimeMillis();  
            int timeAlive = (int) ((timeNow - creationTime)/1000);  
            synchronized (manager) {  
                if (timeAlive > manager.getSessionMaxAliveTime()) {  
                    manager.setSessionMaxAliveTime(timeAlive);  
                }  
                int numExpired = manager.getExpiredSessions();  
                numExpired++;  
                manager.setExpiredSessions(numExpired);  
                int average = manager.getSessionAverageAliveTime();  
                average = ((average * (numExpired-1)) + timeAlive)/numExpired;  
                manager.setSessionAverageAliveTime(average);  
            }  
  
            // 将此session从manager对象的session池中删除  
            manager.remove(this);  
            ......  
        }  
    }  

 

Session的持久化 和 启动初始化:

   tomcat执行安全退出时(通过执行shutdown脚本),会将session持久化到本地文件,通常在tomcat的部署目录下有个session.ser文件。当启动tomcat时,会从这个文件读入session,并添加到manager的session池中    去。 这样,当tomcat正常重启时, session没有丢失,对于用户而言,体会不到重启,不影响用户体验。 

   可以把会话信息写入文件,也可以存入数据库中!

 

  

分享到:
评论

相关推荐

    集中式session管理方案

    集中式Session管理方案是解决多应用、多服务器之间Session共享问题的一种有效方法,尤其在分布式系统和集群环境中显得尤为重要。这种方案旨在确保用户在不同应用系统之间切换时,其Session信息能够保持一致,提供...

    tomcat-redis-session管理 使用说明

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

    Swift 实现的简单的 Session 管理库.zip

    在iOS、macOS或其他使用Swift开发的平台上,Session管理对于处理网络请求、保持用户登录状态、管理应用程序状态至关重要。下面将详细介绍这个项目中的关键知识点。 1. **Swift编程语言**: Swift 是苹果公司推出的...

    webservice6 跨越session管理

    【跨服务Session管理详解】 在Web服务开发中,Session管理是一项关键任务,特别是在涉及多个相关服务的复杂系统中。跨服务Session管理允许不同Web服务之间共享用户的状态信息,确保在整个应用流程中用户的一致性...

    tomcat8专用session管理包.rar

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

    shiro+redis做session管理

    在IT行业中,Session管理是Web应用中的重要环节,它用于维护用户登录状态,确保用户在不同请求间的数据一致性。在大型分布式系统中,由于多台服务器之间无法共享内存,传统的Session管理方式不再适用。这时,我们...

    springsession管理多台tomcatsession

    SpringSession 是一个强大的框架,它扩展了 Spring Framework 的 Session 支持,允许开发者在分布式环境中管理用户会话。尤其在处理多台 Tomcat 服务器时,SpringSession 提供了一种优雅的方式来实现 session 共享,...

    集中式session管理方案(2)

    集中式Session管理方案是一种在分布式环境中解决多个应用服务器之间共享用户会话状态的技术。这种方案主要解决了在多台服务器上部署的应用系统如何协同处理用户的Session数据,确保用户在不同服务器间的无缝切换,...

    session管理

    **Session管理**是Web...总的来说,Session管理是Web应用程序中不可或缺的一部分,理解其原理和优化策略对于开发高质量的Web应用至关重要。在实际应用中,开发者需要根据项目需求和服务器资源合理选择和使用Session。

    Spring中自定义session管理,SpringSession的使用

    在Spring框架中,Session管理是实现用户会话跟踪的关键部分,尤其在分布式系统中,传统的HttpSession面临跨服务器共享的问题。SpringSession的引入解决了这个问题,它提供了一种在多个应用服务器之间共享Session数据...

    通过 Spring Session 实现新一代的 Session 管理.docx

    【Spring Session】是一种创新的解决方案,旨在应对现代云环境下的Session管理挑战。随着微服务架构和高度可扩展的原生云应用的普及,传统的Java EE Session管理方式已无法满足需求。Spring Session API 提供了一种...

    Go-Packagesession为Macaron提供session管理

    "Go-Packagesession为Macaron提供session管理"这个主题意味着我们将深入探讨如何在Macaron框架中使用session管理来维持用户会话。 session在Web开发中扮演着重要的角色,它允许服务器存储关于用户状态的信息,即使...

    Hibernate(session管理)

    本文将深入探讨Hibernate中的核心概念——Session管理。 首先,理解Session在Hibernate中的角色至关重要。Session是Hibernate的主要工作单元,它是应用程序与数据库之间的桥梁。它负责保存、检索和更新Java对象,...

    Javascript 密码保护和Session 管理

    在这个“JavaScript密码保护和Session管理”的主题中,我们将深入探讨如何利用JavaScript实现用户登录的安全性和会话管理的有效性。 首先,密码保护是任何在线应用的基础。在`demo1.html`、`admin.html`等网页中,...

    使用ThreadLocal管理“session”数据

    总结,ThreadLocal是Java中处理线程局部数据的利器,特别适用于需要线程隔离的场景,如Web应用中的session管理。通过合理使用ThreadLocal,可以提升程序的并发性能并保证数据安全性。但同时,需要注意内存管理和避免...

    Android用户Session管理的设计方案.docx

    ### Android用户Session管理的设计方案 #### 一、引言 在Android应用开发中,用户Session管理是一项基础且重要的功能。合理的Session管理方案不仅能提升用户体验,还能有效保障数据安全。本文档将详细介绍一种基于...

    sna集中式session管理实现服务器集群及客户端程序

    sna集中式session管理实现服务器集群及客户端程序,以“单点登陆、session共享解决方案(2)”为基础建立的服务器机群应用,运行server.bat启动服务器端,将client包导入web工程,通过Client.sessionPut()等方法调用。...

    Go-GosessionGo编程语言最快的Websession管理器

    总结,Go-Gosession是Go语言中用于Web session管理的一个强大工具,它提供了高性能、兼容性和灵活性,使得开发者能够轻松地在不同的Web框架下实现用户会话管理。正确理解和使用session管理对于构建健壮的Web应用至关...

    TongWeb V7.0 服务配置指南

    该指南详细介绍了TongWeb V7.0 的配置过程,涵盖了Session管理、RedisSession架构模式、TongWeb-MQ使用说明、普通证书、国密证书、加密传输密钥管理、健康检测等方面的知识点。 Session管理是TongWeb V7.0 中的一...

    zookeeper分布session式实现

    ### 基于ZooKeeper的分布式Session实现详解 #### 1. 认识ZooKeeper ZooKeeper,形象地被称为“动物园管理...通过利用ZooKeeper的特性,可以有效地克服分布式环境下Session管理的挑战,提高系统的整体性能和用户体验。

Global site tag (gtag.js) - Google Analytics