Tomcat中session詳解(原始碼閱讀)

小鞅發表於2016-05-08

Tomcat中的session是通過一個manager來管理的,其中Session介面預設實現類有StandardSession,管理器的預設實現是StandardManager。
我們平時在servlet中使用的session也就是HashMap中的一個session物件,同時session除了在記憶體儲存,同時還提供了持久化方法,tomcat中持久化有兩種,一種是儲存為檔案,另一種則是儲存到資料庫。
這一節首先來看一下預設的StandardSession和StandardManager。


public interface Session {

    // ----------------------------------------------------- Manifest Constants

    public static final String SESSION_CREATED_EVENT = "createSession";

    public static final String SESSION_DESTROYED_EVENT = "destroySession";

    // ------------------------------------------------------------- Properties

    public String getAuthType();

    public void setAuthType(String authType);

    public long getCreationTime();

    public void setCreationTime(long time);

    public String getId();

    public void setId(String id);

    public String getInfo();

    public long getLastAccessedTime();

    public Manager getManager();

    public void setManager(Manager manager);

    public int getMaxInactiveInterval();

    public void setMaxInactiveInterval(int interval);

    public void setNew(boolean isNew);

    public Principal getPrincipal();

    public void setPrincipal(Principal principal);

    public HttpSession getSession();

    public void setValid(boolean isValid);

    public boolean isValid();

    // --------------------------------------------------------- Public Methods

    public void access();

    public void addSessionListener(SessionListener listener);

    public void expire();

    public Object getNote(String name);

    public Iterator getNoteNames();

    public void recycle();

    public void removeNote(String name);

    public void removeSessionListener(SessionListener listener);

    public void setNote(String name, Object value);

}

1.StandardManager中整個啟動過程


 public void start() throws LifecycleException {

        if (debug >= 1)
            log("Starting");

        // Validate and update our current component state
        if (started)
            throw new LifecycleException
                (sm.getString("standardManager.alreadyStarted"));
        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Force initialization of the random number generator
        if (debug >= 1)
            log("Force random number initialization starting");
        String dummy = generateSessionId();
        if (debug >= 1)
            log("Force random number initialization completed");

        // Load unloaded sessions, if any
        try {
            //用於載入持久化的session,載入以後放入sessions(hashMap)中
            load();
        } catch (Throwable t) {
            log(sm.getString("standardManager.managerLoad"), t);
        }

        // Start the background reaper thread
        threadStart();

    }
//啟動一個管理器執行緒,用於實現自動重新載入
 private void threadStart() {

        if (thread != null)
            return;

        threadDone = false;
        threadName = "StandardManager[" + container.getName() + "]";
        thread = new Thread(this, threadName);
        thread.setDaemon(true);
        thread.setContextClassLoader(container.getLoader().getClassLoader());
        thread.start();

    }


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

        // Loop until the termination semaphore is set
        while (!threadDone) {
            threadSleep();
            processExpires();
        }

    }

 private void threadSleep() {

        try {
            Thread.sleep(checkInterval * 1000L);
        } catch (InterruptedException e) {
            ;
        }

    }

 /**
     * Invalidate all sessions that have expired.
     */
    //管理StandardSession中session,去除無效的session
    private void processExpires() {

        long timeNow = System.currentTimeMillis();
        //獲取存活的sessions
        Session sessions[] = findSessions();

        for (int i = 0; i < sessions.length; i++) {
            StandardSession session = (StandardSession) sessions[i];
            //有效,則不移除
            if (!session.isValid())
                continue;
            int maxInactiveInterval = session.getMaxInactiveInterval();
            //如果設定最大存活時間是-1,則不終止
            if (maxInactiveInterval < 0)
                continue;
            int timeIdle = // Truncate, do not round up 
                (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
            if (timeIdle >= maxInactiveInterval) {
                try {
                    session.expire();
                } catch (Throwable t) {
                    log(sm.getString("standardManager.expireException"), t);
                }
            }
        }

    }


2.StandardManager中整個停止過程

   public void stop() throws LifecycleException {

        if (debug >= 1)
            log("Stopping");

        // Validate and update our current component state
        if (!started)
            throw new LifecycleException
                (sm.getString("standardManager.notStarted"));
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;

        // Stop the background reaper thread
        threadStop();

        // Write out sessions
        try {
            //將存活的session持久化
            unload();
        } catch (IOException e) {
            log(sm.getString("standardManager.managerUnload"), e);
        }

        // Expire all active sessions
        Session sessions[] = findSessions();
        for (int i = 0; i < sessions.length; i++) {
            StandardSession session = (StandardSession) sessions[i];
            if (!session.isValid())
                continue;
            try {
            //終止所有的session
                session.expire();
            } catch (Throwable t) {
                ;
            }
        }

        // Require a new random number generator if we are restarted
        this.random = null;


 private void threadStop() {

        if (thread == null)
            return;

        threadDone = true;
        //將當前執行緒設定為中斷狀態
        thread.interrupt();
        try {
            //當前執行緒被掛起,直達thread執行緒結束才執行改執行緒
            thread.join();
        } catch (InterruptedException e) {
            ;
        }

        thread = null;

    }

1.StandardManager中建立一個session

 public Session createSession() {

        if ((maxActiveSessions >= 0) &&
          (sessions.size() >= maxActiveSessions))
            throw new IllegalStateException
                (sm.getString("standardManager.createSession.ise"));
//實際呼叫的是ManagerBase中的creatSession()方法
        return (super.createSession());

    }
 //ManagerBase類中creatSession方法
    public Session createSession() {

        // Recycle or create a Session instance
        Session session = null;
        synchronized (recycled) {
            int size = recycled.size();
            if (size > 0) {
                session = (Session) recycled.get(size - 1);
                recycled.remove(size - 1);
            }
        }
        if (session != null)
            session.setManager(this);
        else
            session = new StandardSession(this);

        // 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;
            session.setId(sessionId);
        }
        /*
        synchronized (sessions) {
            while (sessions.get(sessionId) != null)        // Guarantee uniqueness
                sessionId = generateSessionId();
        }
        */
        session.setId(sessionId);

        return (session);

    }
<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

相關文章