分享

解读 Tomcat源码 -- Session 管理

 CevenCheng 2011-10-28

由于项目中涉及Session的实现,  简单的看了一下Tomcat的Session实现。
主要看了2个类:StandardSession, StandardManager

StandardManager.java 
用来管理session,  session保存在HashMap容器里。
StandManager在后台启动个Daemon线程,每经过checkInterval秒(默认是60s)检查一次失效的session. 然后从HashMap容器里删除。



    /**
     * The background thread that checks for session timeouts and shutdown.
     
*/
    
public void run() ...{

        
// Loop until the termination semaphore is set
        while (!threadDone) ...{
            threadSleep();
            processExpires(); 
// 遍历所有session, 终止失效超时的session
        }

    }

    
/** *//**
     * Invalidate all sessions that have expired.
     
*/
    
private void processExpires() ...{

        
long timeNow = System.currentTimeMillis();
        Session sessions[] 
= findSessions();

        
for (int i = 0; i < sessions.length; i++) ...{
            StandardSession session 
= (StandardSession) sessions[i];
            
if (!session.isValid())
                
continue;
            
int maxInactiveInterval = session.getMaxInactiveInterval();
            
if (maxInactiveInterval < 0)
                
continue;
            
int timeIdle = // Truncate, do not round up
                (int) ((timeNow - session.getLastUsedTime()) / 1000L);
            
if (timeIdle >= maxInactiveInterval) ...{
                
try ...{
                    expiredSessions
++;
                    session.expire(); 
// 终止超时的session
                } catch (Throwable t) ...{
                    log(sm.getString(
"standardManager.expireException"), t);
                }
            }
        }

    }


StandardSession.java 
session的属性值attributes用HashMap来保存。



     /** 
     * 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) ...{

        
// Mark this session as "being expired" if needed
        if (expiring)
            
return;
        expiring 
= true;
        setValid(
false);

        
// Remove this session from our manager''s active sessions
        if (manager != null)
            manager.remove(
this); // 在StandardManager中删除该session

        
// Unbind any objects associated with this session
        String keys[] = keys();
        
for (int i = 0; i < keys.length; i++)
            removeAttribute(keys[i], notify); 
//删除所有属性

        
// Notify interested session event listeners
        if (notify) ...{
            fireSessionEvent(Session.SESSION_DESTROYED_EVENT, 
null);  //触发session listener
        }

        
// Notify interested application event listeners
        
// FIXME - Assumes we call listeners in reverse order
        Context context = (Context) manager.getContainer();
        Object listeners[] 
= context.getApplicationListeners();
        
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) ...{
                        ;
                    }
                    
// FIXME - should we do anything besides log these?
                    log(sm.getString("standardSession.sessionEvent"), t);
                }
            }
        }

        
// We have completed expire of this session
        expiring = false;
        
if ((manager != null&& (manager instanceof ManagerBase)) ...{
            recycle();
        }

    }

创建session的代码在ManagerBase里实现,ManagerBase是StandardManager的父类
创建session中有涉及sessionId的生成, 代码如下:



    /**
     * Construct and return a new session object, based on the default
     * settings specified by this Manager''s properties.  The session
     * id will be assigned by this method, and available via the getId()
     * method of the returned session.  If a new session cannot be created
     * for any reason, return <code>null</code>.
     *
     * 
@exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     
*/
    
public Session createSession() {

        
// 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 sessionId 
= generateSessionId();

        String jvmRoute 
= getJvmRoute();
        
// @todo Move appending of jvmRoute generateSessionId()???
        if (jvmRoute != null) {
            sessionId 
+= ''.'' + jvmRoute;
        }
        
synchronized (sessions) {
            
while (sessions.get(sessionId) != null){ // Guarantee uniqueness
                sessionId = generateSessionId();
                duplicates
++;
                
// @todo Move appending of jvmRoute generateSessionId()???
                if (jvmRoute != null) {
                    sessionId 
+= ''.'' + jvmRoute;
                }
            }
        }

        session.setId(sessionId);
        sessionCounter
++;

        
return (session);

    }
   
/**
     * Generate and return a new session identifier.
     
*/
    
protected synchronized String generateSessionId() {

        
// Generate a byte array containing a session identifier
        Random random = getRandom();  // 取随机数发生器, 默认是SecureRandom
        byte bytes[] = new byte[SESSION_ID_BYTES];
        getRandom().nextBytes(bytes); 
//产生16字节的byte
        bytes = getDigest().digest(bytes); // 取摘要,默认是"MD5"算法

        
// Render the result as a String of hexadecimal digits
        StringBuffer result = new StringBuffer();
        
for (int i = 0; i < bytes.length; i++) {     //转化为16进制字符串
            byte b1 = (byte) ((bytes[i] & 0xf0>> 4);
            
byte b2 = (byte) (bytes[i] & 0x0f);
            
if (b1 < 10)
                result.append((
char) (''0'' + b1));
            
else
                result.append((
char) (''A'' + (b1 - 10)));
            
if (b2 < 10)
                result.append((
char) (''0'' + b2));
            
else
                result.append((
char) (''A'' + (b2 - 10)));
        }
        
return (result.toString());

    }

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多