`
he_wen
  • 浏览: 238647 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

《How Tomcat Works》翻译(9) 之 会话管理

阅读更多

 

第九章、会话管理

一、前言部分

 

Catalina通过一个叫做manager的组件来支持会话管理,它是由org.apache.catalina.Manager接口代表。A manager一直与context相关联,还有就是manager负责创建、更新、销毁会话对象同时也会返回任何组件所需要的有效的会话对象。

 

一个servlet通过调用javax.servlet.http.HttpServletRequest接口中的getSession方法获得一个session对象,该接口是在默认连接器里由org.apache.catalina.connector.HttpRequestBase类实现的。这里在HttpRequestBase类中有一些相关的方法。

 

 

 

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

    }

 

默认下,一个manager把所有的sessions对象存储在内存中。然而,Tomcat也允许一个manager把会话对象存放在文件只能够或者数据库(通过JDBC)。Catalina提供了org.apache.catalina.session包,里面包含了会话对象和会话管理类型。

 

这章从三个部分解释在Catalina中的会话管理:"Session", " Managers ",  " Stores ".最后部分就用Context关联manager来解释这个应用程序。

 

二、会话

 

在servlet程序设计中,一个会话对象由javax.servlet.http.HttpSession接口代表,此接口实现的类是StandardSession(在org.apache.catalina.session包中)。然而,对于安全考虑,manager不会传给一个StandardSession实例给servlet,相反它把自己封装了一次,该类的名字是StandardSessionFacade(在org.apache.catalina.session包中)。注解:看到没有又用来了门面模式啦。。。。 。实际上,manager与另外一个门面(org.apache.catalina.Session接口)协调工作。下面的UML图是关于会话相关的类型。注意为了使图精简我就把org.apache.catalina的前缀(Session, StandardSession,StandardSessionFacade)去掉.

 


三、The Session 接口

 

The Session 接口充当了Catalina内部门面角色。the Session接口的标准实现是StandardSession类,同时它也实现了javax.servlet.http.HttpSession接口,The Session接口下面的代码:

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


}
 

一个会话对象一直包含在一个manager中,the setManager和getManager方法目的是一个会话实例与一个manager相关联. 一个会话实例同时也有一个唯一的标志符( 通过The Context相关联的manager),Session标识符也能够被the setId和getId方法访问。the manager决定一个会话对象的有效性来调用The getLastAccessedTime方法,The manager调用了setValid方法是设置或者是重新设置一个会话对象的有效性。只要每次会话实例被访问,那么其方法就会被调用最近更新时间。最后,The manager能够使得一个会话对象过期,通过调用the expire方法; the getSession方法返回一个门面封装了的HttpSession对象。

 

四、The StandardSession类

 

The StandardSession类是实现The Session接口的标准实现。除此之外他还实现了javax.servlet.http.HttpSession接口和java.lang.Serializable(这个是为了使得会话对象能够序列化)接口。

 

The standardSession的构造函数接收一个Manager实例,目的是使得一个会话对象一直拥有一个Manager.

 

     public StandardSession(Manager manager);

 

下面有一些重要的私有变量来维护状态, 注意the transient关键字是让这些变量不能序列化。

 



 注意:在Tomcat5中以上的变量时保护的,而在Tomcat 4 中是私有变量。每个变量都有get/set 方法。

 

The getSession方法通过传this实例创建一个StandardSessionFacade对象:

 

  public HttpSession getSession(){

       if(facade == null)

                        facade=new StandardSessionFacade(this);

            return facade;

  }

 

在Manager中如果一个会话对象没有访问的这个时间段超出了the maxInactiveInternal变量的值那么此会话就过期。能使一个会话对象过期,是通过调用了The Session接口的expire方法。下面就给出在Tomcat 4中,在StanardSession类实现了这个接口的方法:

 

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

    }
 

 

 

 

该方法的处理过程包括:设置内部变量,从Manager中移除The Session实例,触发一些事件。

 

五、The StandardSessionFacade类

 

为了传一个session对象给Servlet,Catalina实例化The StandardSession类并封装这个实例,在把它传给Servlet.  然而,传给Servlet的是一个StandardSessionFacade实例( 该类仅仅实现了javax.servlet.http.HttpSession接口 ),那为什么要这么做呢?答案是:为了让servlet程序设计者编程时,无法让HttpSession对象向上转型为StandardSession,这是因为仅仅让程序设计者访问公共的方法,而一些私有的方法不暴露给程序设计者。

 

六、Manager

 

一个Manager管理会话对象,例如:它能创建会话对象,也能销毁会话对象。一个Manager由org.apache.catalina.Manager接口代表。在Catalina中,the org.apache.catalina.session包中,包含了ManagerBase类(它实现了公有的功能)。The ManagerBase有两个直接的子类:StandardManager和PersistentManagerBase.

 

当容器运行时,The StandardManager在内存中存储会话对象。然而,如果停止,那么StandardManager把当前内存中所有的会话对象存储在一个文件中,当又重新启动时,又会重新加载这些会话对象。

 

PersistentManagerBase是manager的一个基本组件(它在二级存储中存储了会话对象),该类也有两个子类: PersistentManager和DistributedManager(给类仅仅在Tomcat 4中能够使用)。下面是UML类图,关于The Manager接口和其实现的类:

 


七、The Manager 接口

 

The Manager接口代表了一个Manager组件,下面是其接口的方法:

 

package org.apache.catalina;


import java.beans.PropertyChangeListener;
import java.io.IOException;
public interface Manager {
    public Container getContainer();


    /**
     * Set the Container with which this Manager is associated.
     *
     * @param container The newly associated Container
     */
    public void setContainer(Container container);


    /**
     * Return the DefaultContext with which this Manager is associated.
     */
    public DefaultContext getDefaultContext();


    /**
     * Set the DefaultContext with which this Manager is associated.
     *
     * @param defaultContext The newly associated DefaultContext
     */
    public void setDefaultContext(DefaultContext defaultContext);



    /**
     * Return the distributable flag for the sessions supported by
     * this Manager.
     */
    public boolean getDistributable();


    /**
     * Set the distributable flag for the sessions supported by this
     * Manager.  If this flag is set, all user data objects added to
     * sessions associated with this manager must implement Serializable.
     *
     * @param distributable The new distributable flag
     */
    public void setDistributable(boolean distributable);


    /**
     * Return descriptive information about this Manager implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    public String getInfo();


    /**
     * Return the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     */
    public int getMaxInactiveInterval();


    /**
     * Set the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     *
     * @param interval The new default value
     */
    public void setMaxInactiveInterval(int interval);


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


    /**
     * Add this Session to the set of active Sessions for this Manager.
     *
     * @param session Session to be added
     */
    public void add(Session session);


    /**
     * Add a property change listener to this component.
     *
     * @param listener The listener to add
     */
    public void addPropertyChangeListener(PropertyChangeListener listener);


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


    /**
     * Return the active Session, associated with this Manager, with the
     * specified session id (if any); otherwise return <code>null</code>.
     *
     * @param id The session id for the session to be returned
     *
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     * @exception IOException if an input/output error occurs while
     *  processing this request
     */
    public Session findSession(String id) throws IOException;


    /**
     * Return the set of active Sessions associated with this Manager.
     * If this Manager has no active Sessions, a zero-length array is returned.
     */
    public Session[] findSessions();


    /**
     * Load any currently active sessions that were previously unloaded
     * to the appropriate persistence mechanism, if any.  If persistence is not
     * supported, this method returns without doing anything.
     *
     * @exception ClassNotFoundException if a serialized class cannot be
     *  found during the reload
     * @exception IOException if an input/output error occurs
     */
    public void load() throws ClassNotFoundException, IOException;


    /**
     * Remove this Session from the active Sessions for this Manager.
     *
     * @param session Session to be removed
     */
    public void remove(Session session);


    /**
     * Remove a property change listener from this component.
     *
     * @param listener The listener to remove
     */
    public void removePropertyChangeListener(PropertyChangeListener listener);

    public void unload() throws IOException;

}
 

首先,The Manager接口有getContainer和setContainer方法目的是一个实现Manager接口类与一个Context相关联。The CreateSession方法就是创建一个会话对象。The add方法把会话实例添加到会花池中,The remove方法是把会话对象从会话池中移除掉。The getMaxInactiveInternal和setMaxInactiveInternal方法返回(and specifices the number of sends the Manager will wait for the user associated with a session to  come back before destorying the session).这里不会翻译。。。悲剧。。。

 

最后,the load和upload方法支持把可持续化的会话存储在第二个存储空间中(这个是有PersistManager中支持可持续化类型机制),The upload方法保存了当前激活的会话对象(也就是第一存储空间中该类时standardManger),并且the Load方法也支持把存储在第二存储空间的会话对象引入到内存中。

 

八、The ManagerBase类

 

The ManagerBase类是一个抽象类( 它的父类是Manager类 )。这个类为它的孩子提供公共的功能,此外,ManagerBase有一个createSession方法创建一个会话对象。每个session有一个唯一的标志符,这个标识符是由保护方法generateSessionId方法返回。

 

注意:一个激活的session是一个有效的会话对象,而没有过期。

 

一个特定的context下的Manager的实例管理整个激活的session. 这些激活的session存储在一个叫sessions的HashMap中:

                 protected HashMap sessions= new HashMap();

The add方法把一个session对象添加到sessions  HashMap中,这个方法请看下面的代码:

 

     public void add(Session session){

 

           synchronized(sessions){

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

 

                }

}

 

The remove方法从HashMap中移除一个会话对象,下面是其方法代码:

 

           public void remove(Session session){

 

                 synchronized(sessions){

                      sessions.remove(session.getId());

 

                  }

  }

 

 The findSession没有参数的方法,是返回全部激活的会话( 来自存放在HashMap中的全部激活的session,他转换成数组

 )。The findSession有参数的方法(session标志符作为参数),它返回一个该标志符对应的一个会话实例。这些重载的方法请看下面代码:

 

 public Session[] findSessions() {

        Session results[] = null;
        synchronized (sessions) {
            results = new Session[sessions.size()];
            results = (Session[]) sessions.values().toArray(results);
        }
        return (results);

    }
public Session findSession(String id) throws IOException {

        if (id == null)
            return (null);
        synchronized (sessions) {
            Session session = (Session) sessions.get(id);
            return (session);
        }

    }
 

 

九、StandardManager

 

The StandardManager类是Manager接口的一个标准实现,在内存中存储了整个会话对象,它也同时实现了The Lifecycle接口(请看在第六章、Lifecycle),这样就可以用start和stop来控制组件。实现stop方法中调用了upload方法(就是序列化有效的session实例到文件中,文件名字叫做SESSIONS.ser)。The SESSIONS.ser文件能够在CATALINA_HOME目录下找到。比如,在Tomcat 4和 Tomcat 5 中,如果 你运行本应用程序的代码,你就会发现在CATALINA_HOME/work/Standalone/localhost/examples目录下能找到SESSIONS.ser文件。当StandardManager有重新启动时,这些会话对象通过调用the Load方法全部读到内存中。

 

 A Manager也负责销毁不再有效的会话对象。在Tomcat 4 中的StandardManager中,这样的实现,它是用了一个专门的线程来实现销毁会话对象。由于这个原因,StandardManager实现了 java.lang.Runnable, 请看下面实现run的方法:

 

 

  public void run() {

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

    }

 

The threadSleep方法调用了threadSleep(里面主要是Thread.sleep(checkInterval * 1000L)),the checkInterval变量是以秒为单位,默认值是60秒,也可以通过调用setCheckInterval方法改变这个值。

 

  The processExpire方法: 循环遍历由StandardManager管理的整个会话对象,每个Session对象实例把lastAccessedTime变量与当前时间相比较。如果当前时间减去 lastAccessedTime的值大于 maxInactiveInternal,那么该方法就会调用The session接口中的expire方法使得会话该对象过期。The maxInactiveInternal的值通过调用setMaxInactiveInternal方法来改变这个值。在StandardManager中的maxInactiveInternal变量默认值是 60. 呵呵呵。。不要愚蠢的认为maxInactiveInternal值是在Tomcat部署的时候设置的。同时,The setContainer方法:它调用了the org.apache.catalina.core.ContainerBase类中的setManager方法(你一直都要调用setManager方法目的是context和Manager相关联),来重写这个值。下面是setContainer方法中的一些代码:

 

       setMaxInactiveInternal((( Context ) this.container ).getSessionTimout() * 60 );

 

 注意:the sessionTimeOut变量的默认值在org.apache.catalina.core.StandardContext类是30秒。在Tomcat 5中,The StandradManager类没有实现 java.lang.Runnable接口。在Tomcat 5 中的StandardManager对象中的The processExpires方法直接调用了the backgroundprocess方法,但是Tomcat 4不是这样做的。

 

      public  void   backgroundProcess(){

               processExpires();

           }

 

 在 StandardManager中的backgroundProcess方法是通过the org.apache.catalina.core.StandardContext实例(the Container和manager相关联)被调用的。StandardContext周期的调用了backgroundProcess方法这个将会在第十二章进行讨论。

 

 

 

十、PersistentManagerBase

 

 The PersistentManagerBase类是整个可持久化管理的父类。StandardManager和 persistent manager主要的区别就是后者存在一个store,一个 store代表可管理session对象的第二级存储,The PersistentManagerBase类使用了一个私有引用对象(叫做store).

 

            private Store store=null;

 

在一个可持久化管理中,整个session对象既能备份有能迁移。当一个会话对象备份时,The session 对象就会拷贝到一个store中,原始的那个还是会继续停留在内存中。因此,如果服务器崩溃了,激活的会话对象能够在the store中恢复过来。当一个session对象被迁移时,它就会被迁移到the store中,那为什么要这么做呢?这是因为,激活的会话对象的数目已经超出了一个特定的值或者The session对象已经停留在内存中太久并且从来没有用到过它。迁移的目的就是保存内存中的会话对象。注意激活的对象就是停留在内存中的对象。

 

 在Tomcat 4 中PersistentManagerBase类实现了java.lang.Runnable接口,目的是使用一个独立的线程周期的备份和迁移激活的会话对象,下面是实现run方法的代码:

 

 

 

 

  • 大小: 81.7 KB
  • 大小: 81.6 KB
  • 大小: 147.6 KB
分享到:
评论
2 楼 hantsy 2010-12-18  
Good job...
最好用 DOCBOOK 组织一下,以便将来发布集中的文档。
我有一个DOCBOOK工具相关的项目,
http://hantsy-labs.googlecode.com
以前我翻译了 Spring Live全书,http://blog.chinaunix.net/u/1096/showart_88617.html
我的博客 http://hantsy.cublog.cn

贵在坚持。
1 楼 zwhua 2010-12-17  
<div class="quote_title">he_wen 写道</div>
<div class="quote_div">
<p> </p>
<p style="text-align: center;"><strong><span style="font-size: large;">第九章、会话管理</span> </strong></p>
<p>一、前言部分</p>
<p> </p>
<p>Catalina通过一个叫做manager的组件来支持会话管理,它是由org.apache.catalina.Manager接口代表。A manager一直与context相关联,还有就是manager负责创建、更新、销毁会话对象同时也会返回任何组件所需要的有效的会话对象。</p>
<p> </p>
<p>一个servlet通过调用javax.servlet.http.HttpServletRequest接口中的getSession方法获得一个session对象,该接口是在默认连接器里由org.apache.catalina.connector.HttpRequestBase类实现的。这里在HttpRequestBase类中有一些相关的方法。</p>
<p> </p>
<p> </p>
<p> </p>
<pre name="code" class="java">  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) &amp;&amp; !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) &amp;&amp; !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) &amp;&amp; (response != null) &amp;&amp;
            context.getCookies() &amp;&amp;
            response.getResponse().isCommitted()) {
            throw new IllegalStateException
              (sm.getString("httpRequestBase.createCommitted"));
        }

        session = manager.createSession();
        if (session != null)
            return (session.getSession());
        else
            return (null);

    }
</pre>
<p> </p>
<p>默认下,一个manager把所有的sessions对象存储在内存中。然而,Tomcat也允许一个manager把会话对象存放在文件只能够或者数据库(通过JDBC)。Catalina提供了org.apache.catalina.session包,里面包含了会话对象和会话管理类型。</p>
<p> </p>
<p>这章从三个部分解释在Catalina中的会话管理:"Session", " Managers ",  " Stores ".最后部分就用Context关联manager来解释这个应用程序。</p>
<p> </p>
<p>二、会话</p>
<p> </p>
<p>在servlet程序设计中,一个会话对象由javax.servlet.http.HttpSession接口代表,此接口实现的类是StandardSession(在org.apache.catalina.session包中)。然而,对于安全考虑,manager不会传给一个StandardSession实例给servlet,相反它把自己封装了一次,该类的名字是StandardSessionFacade(在org.apache.catalina.session包中)。<span style="background-color: #ff0000;">注解:看到没有又用来了门面模式啦。。。。</span> 。实际上,manager与另外一个门面(org.apache.catalina.Session接口)协调工作。下面的UML图是关于会话相关的类型。注意为了使图精简我就把org.apache.catalina的前缀(Session, StandardSession,StandardSessionFacade)去掉.</p>
<p> </p>
<p><br><img src="http://dl.iteye.com/upload/attachment/362896/8c0b2878-108f-37ed-8ab8-2634afad2f5f.png" alt=""></p>
<p>三、The Session 接口</p>
<p> </p>
<p>The Session 接口充当了Catalina内部门面角色。the Session接口的标准实现是StandardSession类,同时它也实现了javax.servlet.http.HttpSession接口,The Session接口下面的代码:</p>
<pre name="code" class="java">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);


}
</pre>
 
<p>一个会话对象一直包含在一个manager中,the setManager和getManager方法目的是一个会话实例与一个manager相关联. 一个会话实例同时也有一个唯一的标志符( 通过The Context相关联的manager),Session标识符也能够被the setId和getId方法访问。the manager决定一个会话对象的有效性来调用The getLastAccessedTime方法,The manager调用了setValid方法是设置或者是重新设置一个会话对象的有效性。只要每次会话实例被访问,那么其方法就会被调用最近更新时间。最后,The manager能够使得一个会话对象过期,通过调用the expire方法; the getSession方法返回一个门面封装了的HttpSession对象。</p>
<p> </p>
<p>四、The StandardSession类</p>
<p> </p>
<p>The StandardSession类是实现The Session接口的标准实现。除此之外他还实现了javax.servlet.http.HttpSession接口和java.lang.Serializable(这个是为了使得会话对象能够序列化)接口。</p>
<p> </p>
<p>The standardSession的构造函数接收一个Manager实例,目的是使得一个会话对象一直拥有一个Manager.</p>
<p> </p>
<p>     public StandardSession(Manager manager);</p>
<p> </p>
<p>下面有一些重要的私有变量来维护状态, 注意the transient关键字是让这些变量不能序列化。</p>
<p> </p>
<p><br><img src="http://dl.iteye.com/upload/attachment/369099/64876f35-4d58-3634-b2e3-7e4f0f78212e.png" alt=""><br> 注意:在Tomcat5中以上的变量时保护的,而在Tomcat 4 中是私有变量。每个变量都有get/set 方法。</p>
<p> </p>
<p>The getSession方法通过传this实例创建一个StandardSessionFacade对象:</p>
<p> </p>
<p>  public HttpSession getSession(){</p>
<p>       if(facade == null)</p>
<p>                        facade=new StandardSessionFacade(this);</p>
<p>            return facade;</p>
<p>  }</p>
<p> </p>
<p>在Manager中如果一个会话对象没有访问的这个时间段超出了the maxInactiveInternal变量的值那么此会话就过期。能使一个会话对象过期,是通过调用了The Session接口的expire方法。下面就给出在Tomcat 4中,在StanardSession类实现了这个接口的方法:</p>
<p> </p>
<pre name="code" class="java">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 &lt; 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 &amp;&amp; (listeners != null)) {
            HttpSessionEvent event =
              new HttpSessionEvent(getSession());
            for (int i = 0; i &lt; 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) &amp;&amp; (manager instanceof ManagerBase)) {
            recycle();
        }

    }</pre>
 
<p> </p>
<p> </p>
<p> </p>
<p>该方法的处理过程包括:设置内部变量,从Manager中移除The Session实例,触发一些事件。</p>
<p> </p>
<p>五、The StandardSessionFacade类</p>
<p> </p>
<p>为了传一个session对象给Servlet,Catalina实例化The StandardSession类并封装这个实例,在把它传给Servlet.  然而,传给Servlet的是一个StandardSessionFacade实例( 该类仅仅实现了javax.servlet.http.HttpSession接口 ),那为什么要这么做呢?答案是:为了让servlet程序设计者编程时,无法让HttpSession对象向上转型为StandardSession,这是因为仅仅让程序设计者访问公共的方法,而一些私有的方法不暴露给程序设计者。</p>
<p> </p>
<p>六、Manager</p>
<p> </p>
<p>一个Manager管理会话对象,例如:它能创建会话对象,也能销毁会话对象。一个Manager由org.apache.catalina.Manager接口代表。在Catalina中,the org.apache.catalina.session包中,包含了ManagerBase类(它实现了公有的功能)。The ManagerBase有两个直接的子类:StandardManager和PersistentManagerBase.</p>
<p> </p>
<p>当容器运行时,The StandardManager在内存中存储会话对象。然而,如果停止,那么StandardManager把当前内存中所有的会话对象存储在一个文件中,当又重新启动时,又会重新加载这些会话对象。</p>
<p> </p>
<p>PersistentManagerBase是manager的一个基本组件(它在二级存储中存储了会话对象),该类也有两个子类: PersistentManager和DistributedManager(给类仅仅在Tomcat 4中能够使用)。下面是UML类图,关于The Manager接口和其实现的类:</p>
<p> </p>
<p><br><img src="http://dl.iteye.com/upload/attachment/369111/8067d00f-edbf-33ae-9b84-2c2c5d5b453e.png" alt=""></p>
<p>七、The Manager 接口</p>
<p> </p>
<p>The Manager接口代表了一个Manager组件,下面是其接口的方法:</p>
<p> </p>
<pre name="code" class="java">package org.apache.catalina;


import java.beans.PropertyChangeListener;
import java.io.IOException;
public interface Manager {
    public Container getContainer();


    /**
     * Set the Container with which this Manager is associated.
     *
     * @param container The newly associated Container
     */
    public void setContainer(Container container);


    /**
     * Return the DefaultContext with which this Manager is associated.
     */
    public DefaultContext getDefaultContext();


    /**
     * Set the DefaultContext with which this Manager is associated.
     *
     * @param defaultContext The newly associated DefaultContext
     */
    public void setDefaultContext(DefaultContext defaultContext);



    /**
     * Return the distributable flag for the sessions supported by
     * this Manager.
     */
    public boolean getDistributable();


    /**
     * Set the distributable flag for the sessions supported by this
     * Manager.  If this flag is set, all user data objects added to
     * sessions associated with this manager must implement Serializable.
     *
     * @param distributable The new distributable flag
     */
    public void setDistributable(boolean distributable);


    /**
     * Return descriptive information about this Manager implementation and
     * the corresponding version number, in the format
     * &lt;code&gt;&amp;lt;description&amp;gt;/&amp;lt;version&amp;gt;&lt;/code&gt;.
     */
    public String getInfo();


    /**
     * Return the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     */
    public int getMaxInactiveInterval();


    /**
     * Set the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     *
     * @param interval The new default value
     */
    public void setMaxInactiveInterval(int interval);


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


    /**
     * Add this Session to the set of active Sessions for this Manager.
     *
     * @param session Session to be added
     */
    public void add(Session session);


    /**
     * Add a property change listener to this component.
     *
     * @param listener The listener to add
     */
    public void addPropertyChangeListener(PropertyChangeListener listener);


    /**
     * 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 &lt;code&gt;null&lt;/code&gt;.
     *
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     */
    public Session createSession();


    /**
     * Return the active Session, associated with this Manager, with the
     * specified session id (if any); otherwise return &lt;code&gt;null&lt;/code&gt;.
     *
     * @param id The session id for the session to be returned
     *
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     * @exception IOException if an input/output error occurs while
     *  processing this request
     */
    public Session findSession(String id) throws IOException;


    /**
     * Return the set of active Sessions associated with this Manager.
     * If this Manager has no active Sessions, a zero-length array is returned.
     */
    public Session[] findSessions();


    /**
     * Load any currently active sessions that were previously unloaded
     * to the appropriate persistence mechanism, if any.  If persistence is not
     * supported, this method returns without doing anything.
     *
     * @exception ClassNotFoundException if a serialized class cannot be
     *  found during the reload
     * @exception IOException if an input/output error occurs
     */
    public void load() throws ClassNotFoundException, IOException;


    /**
     * Remove this Session from the active Sessions for this Manager.
     *
     * @param session Session to be removed
     */
    public void remove(Session session);


    /**
     * Remove a property change listener from this component.
     *
     * @param listener The listener to remove
     */
    public void removePropertyChangeListener(PropertyChangeListener listener);

    public void unload() throws IOException;

}
</pre>
 
<p>首先,The Manager接口有getContainer和setContainer方法目的是一个实现Manager接口类与一个Context相关联。The CreateSession方法就是创建一个会话对象。The add方法把会话实例添加到会花池<span style="background-color: #ff0000;">中,The remove方法是把会话对象从会话池中移除掉。The getMaxInactiveInternal和setMaxInactiveInternal方法返回(and specifices the number of sends the Manager will wait for the user associated with a session to  come back before destorying the session).这里不会翻译。。。悲剧。。。</span> </p>
<p> </p>
<p>最后,the load和upload方法支持把可持续化的会话存储在第二个存储空间中(这个是有PersistManager中支持可持续化类型机制),The upload方法保存了当前激活的会话对象(也就是第一存储空间中该类时standardManger),并且the Load方法也支持把存储在第二存储空间的会话对象引入到内存中。</p>
<p> </p>
<p>八、The ManagerBase类</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
</div>
<p> </p>

相关推荐

    How Tomcat Works 中文版.pdf

    通过阅读《How Tomcat Works》中文版,读者将能够获得对Tomcat架构的全面理解,学习到如何从源码级别研究和开发一个高性能的Java应用服务器,以及如何将其应用于实际的Web开发和服务器管理工作中。

    How Tomcat Works【英文PDF+中文HTML+源码】.zip

    9. **源码分析**:深入源码有助于理解Tomcat的工作流程,例如Servlet容器如何解析请求、如何调用Servlet的生命周期方法,以及如何处理会话管理等。 10. **扩展性**:Tomcat可以通过添加Valve组件来扩展其功能,...

    How Tomcat Works中文

    ### How Tomcat Works中文版深度解析 #### 一、引言与概述 《How Tomcat Works》是一本针对Apache Tomcat服务器内部工作机制进行深入剖析的专业书籍。本书详细介绍了Tomcat 4.1.12和5.0.18两个版本的内部结构与...

    How Tomcat Works 中文版

    《How Tomcat Works中文版》这本书是一本深入探讨Apache Tomcat服务器工作原理的专著。Apache Tomcat服务器,或简称为Tomcat,是世界上广泛使用的Java Servlet容器和JavaServer Pages(JSP)引擎,负责处理基于Java...

    HowTomcatWorks 中文版+源码.rar

    首先,从标题和描述我们可以得知,这个压缩包包含两部分内容:《HowTomcatWorks》的中文翻译和源码。这使得我们能够从理论和实践两个层面去了解Tomcat。中文版的书籍可以帮助中国开发者消除语言障碍,更深入地理解...

    HowTomcatWorks(书和源码)

    《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,同时也包含了源码,为读者提供了理论与实践相结合的深入学习体验。Tomcat是一款广泛使用的开源Java Servlet容器,它是Apache软件基金会 Jakarta...

    how tomcat works 中文版及源码

    通过阅读《How Tomcat Works》中文版和分析源码,开发者不仅可以了解到Tomcat的基本架构,还能深入到细节,理解其在处理请求、管理会话、加载资源等方面的具体实现。这对于优化Web应用性能、调试问题、扩展Tomcat...

    HowTomcatWorks-master.zip

    "HowTomcatWorks"项目,正如其名,旨在帮助开发者了解Tomcat的工作原理,通过源代码分享,使我们有机会深入探究这个强大的服务器内部机制。 1. **Tomcat架构概览** Tomcat的架构设计分为几个主要部分:Catalina...

    How tomcat works(包含源码示例)

    《How Tomcat Works》这本书深入剖析了Tomcat服务器的工作原理,是Java开发者深入理解Servlet容器不可或缺的参考资料。Tomcat作为Apache软件基金会的项目,是开源的、轻量级的Servlet和JSP容器,广泛应用于各种Web...

    how tomcat works

    《How Tomcat Works》这本书详细解释了Tomcat的工作原理,它不仅为新手提供了一个蓝图,帮助他们理解这个复杂的系统,也为有经验的开发者提供了深入学习的机会。 ### Tomcat的基本概念 Tomcat核心分为两个主要模块...

    how tomcat works中英文版

    通过阅读源码,开发者可以了解Tomcat内部的详细实现,包括线程池管理、会话管理、安全控制等,这对于解决复杂问题和定制化开发非常有帮助。 在实际操作中,还会涉及到Tomcat的部署和配置,如修改server.xml配置文件...

    how tomcat works( 深入剖析tomcat) 的随书源码

    Tomcat提供JNDI服务,允许Web应用查找和绑定资源,如数据源、邮件会话等,方便应用的配置和管理。 10. **性能优化** Tomcat的性能可以通过调整各种配置参数进行优化,如最大线程数、最小空闲线程数、连接超时、...

    how-tomcat-works-master_howtomcatworks_

    "how-tomcat-works-master_howtomcatworks_"是一个关于Tomcat工作原理的源码分析项目,经过整理后可以在IntelliJ IDEA中直接运行,为开发者提供了一手的实践平台。 首先,我们要了解Tomcat的核心组件。Tomcat主要由...

    译How Tomcat Works(第二章)

    《译How Tomcat Works(第二章)》这篇文章主要讲解了Apache Tomcat服务器的工作原理,它是一个开源的Java Servlet容器,广泛用于部署Web应用程序。在这一章中,我们将深入探讨Tomcat如何处理HTTP请求,以及其内部架构...

Global site tag (gtag.js) - Google Analytics