How Tomcat Works學習筆記

 

Session管理

         通過manager組件,catalina支持對會話(session)進行管理,manager組件表示爲org.apache.catalina.Manager接口。管理器通常是與context一起協同工作。創建、修改和銷燬session是manager的主要責任,當然它也負責像所有的request提供一個有效的session。

         一個servlet可以通過調用javax.servlet.http.HttpServletRequest接口的getSession方法獲取會話,方法的實現在org.apache.catalina.connector.HttpReqestBase類裏面:

public HttpSession getSession() {

        return (getSession(true));

    }

    public HttpSession getSession(boolean create) {

        if( System.getSecurityManager() != null ) {

            PrivilegedGetSession dp = new PrivilegedGetSession(create);

            return (HttpSession)AccessController.doPrivileged(dp);

        }

        return doGetSession(create);

    }

    private HttpSession doGetSession(boolean create) {

        // There cannot be a session if no context has been assigned yet

        if (context == null)

            return (null);

        // Return the current session if it exists and is valid

        if ((session != null) && !session.isValid())

            session = null;

        if (session != null)

            return (session.getSession());

        // Return the requested session if it exists and is valid

        Manager manager = null;

        if (context != null)

            manager = context.getManager();

        if (manager == null)

            return (null);      // Sessions are not supported

        if (requestedSessionId != null) {

            try {

                session = manager.findSession(requestedSessionId);

            } catch (IOException e) {

                session = null;

            }

            if ((session != null) && !session.isValid())

                session = null;

            if (session != null) {

                return (session.getSession());

            }

        }

        // Create a new session if requested and the response is not committed

        if (!create)

            return (null);

        if ((context != null) && (response != null) &&

            context.getCookies() &&

            response.getResponse().isCommitted()) {

            throw new IllegalStateException

              (sm.getString("httpRequestBase.createCommitted"));

        }

        session = manager.createSession();

        if (session != null)

            return (session.getSession());

        else

            return (null);

}

         默認情況下,管理器把它管理的session保存在內存中,同時也支持對session進行持久化,保存到文件或數據庫當中。

會話(Session)

         在servlet編程當中,會話(session)對象用javax.servlet.http.HttpSession接口表示,其的基本實現類是org.apache.catalina.session包中StandardSession,出於安全考慮並不直接把該類提供給servlet,而是爲其提供了一個門面類StandardSessionFacade,相關類圖:

        

Session接口

         Session是catalina內部門面,其實現類StandardSession同時也實現了javax.servlet.http.HttpSession接口,接口定義如下:

         package org.apache.catalina;

import java.security.Principal;

import java.util.Iterator;

import javax.servlet.http.HttpSession;

public interface Session {

        public static final String SESSION_CREATED_EVENT = "createSession";

        public static final String SESSION_DESTROYED_EVENT = "destroySession";

        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 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);

}

Session對象通常包含在管理器中,所以這裏需要一個setManager和getManager方法,以便把session分配給容器,每個session通常需要一個唯一標識。

StandardSession類

    StandardSession類是Session接口的標準實現類,同時也實現了HttpSession接口,因爲需要存儲,它也是可序列號的,它的構造函數中需要提供一個Manager實例:

         public StandardSession(Manager manager) {

        super();

        this.manager = manager;

        if (manager instanceof ManagerBase)

            this.debug = ((ManagerBase) manager).getDebug();

}

提供一個getSession方法會返回StandarSession的門面類:

         public HttpSession getSession() {

        if (facade == null)

            facade = new StandardSessionFacade(this);

        return (facade);

}

一旦在一個指定的時間內沒有操作會話,那麼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);

        // 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);

        }

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

        }

}

StandardSessionFacade類

    爲了防止servlet操作session接口中的一些方法,catalina中爲StandardSession類提供了一個門面類,只允許servlet調用HttpSession中的方法。

管理器(Manager)

    管理器用來管理session對象,Tomcat中定義了管理器接口:org.apache.catalina.Manager,同時提供了一個實現了管理器的公共方法的ManagerBase類,ManagerBase有兩個子類:StandardManager和PersistentManagerBase。

    在運行時,StandardManager把session保存在內存中,停止是會寫入文件中,再次使用時又會從文件把這些session重新加載到內存當中,Manager的實現關係圖如下:

   

    其中DistributeManager只在Tomcat4中有。

Manager接口

Manager表示管理器組件,接口定義如下:

         package org.apache.catalina;

import java.beans.PropertyChangeListener;

import java.io.IOException;

public interface Manager {

    public Container getContainer();

    public void setContainer(Container container);

    public DefaultContext getDefaultContext();

    public void setDefaultContext(DefaultContext defaultContext);

    public boolean getDistributable();

    public void setDistributable(boolean distributable);

    public String getInfo();

    public int getMaxInactiveInterval();

    public void setMaxInactiveInterval(int interval);

    public void add(Session session);

    public void addPropertyChangeListener(PropertyChangeListener listener);

    public Session createSession();

    public Session findSession(String id) throws IOException;

    public Session[] findSessions();

    public void load() throws ClassNotFoundException, IOException;

    public void remove(Session session);

    public void removePropertyChangeListener(PropertyChangeListener listener);

    public void unload() throws IOException;

}

首先,通過getContainer和setContainer方法可以把Manager分配個context容器,creatSession方法創建一個session對象,add方法把session添加到緩衝池中,remove方法把session從緩衝池中移除,getMaxInactiveInterval和setMaxInactiveInterval方法設置當用戶沒有操作會話以後管理器銷燬session的最大間隔秒數。

其次,load和upload方法支持把session持久化到數據庫磁盤等存儲器中。

ManagerBase類

         ManagerBase是一個抽象類,提供了對Manager接口的一些公共方法的實現。generateSessionId返回一個唯一的session標識。

         所有的活動的session被緩存在Map中:

protected HashMap sessions = new HashMap();

    向緩存map中添加移除session對象:

                   public void add(Session session) {

             synchronized (sessions) {

                 sessions.put(session.getId(), session);

             }

        }

                   public void remove(Session session) {

             synchronized (sessions) {

                 sessions.remove(session.getId());

             }

        }

    查找相應session:

       public Session findSession(String id) throws IOException {

             if (id == null)

                 return (null);

             synchronized (sessions) {

                 Session session = (Session) sessions.get(id);

                 return (session);

             }

        }

        public Session[] findSessions() {

             Session results[] = null;

             synchronized (sessions) {

                 results = new Session[sessions.size()];

                 results = (Session[]) sessions.values().toArray(results);

             }

             return (results);

        }

StandardManager類

    StandardManager是Manager的標準實現類,會把session保存在內存中。它實現了LifeCycle接口,所以它可以啓動和停止:

    public void run() {

        // Loop until the termination semaphore is set

        while (!threadDone) {

            threadSleep();

            processExpires();

        }

}

PersistentManagerBase類

    PersistentManagerBase類是所有持久化Manager的父類。

Stores

         Manager通過org.apache.catalina.Store接口來管理session存儲,接口定義如下:

         package org.apache.catalina;

import java.beans.PropertyChangeListener;

import java.io.IOException;

public interface Store {

        public String getInfo();

        public Manager getManager();

        public void setManager(Manager manager);

        public int getSize() throws IOException;

        public void addPropertyChangeListener(PropertyChangeListener listener);

        public String[] keys() throws IOException;

        public Session load(String id)throws ClassNotFoundException, IOException;

        public void remove(String id) throws IOException;

        public void clear() throws IOException;

        public void removePropertyChangeListener(PropertyChangeListener listener);

        public void save(Session session) throws IOException;

}

最重要的是save和load方法,用來保存和加載session,有一個StoreBase類提供公共方法的實現,StoreBase類有兩個類FileStore和JDBCStore,分別把session保存在文件和數據庫中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章