初探Tomcat源码 (8) —— Session_StandardSession

        上一章讨论过Tomcat5.0中Catalina通过Manager来完成session的管理,这章我们来看看Session的标准实现:StandardSession。


StandardSession

        StandardSession除了实现了javax.servlet.http.HttpSession和org.apache.catalina.Session之外,它还实现了java.lang.Serializable接口来使得Session对象可序列化,这为了后面的Session的持久化做准备。其实如果配置不持久化的话,也可以不实现序列化。

publicStandardSession(Manager manager)

 

        由于一个Session对象常常被一个管理器持有,所以接口提供了setManagergetManager方法来关联一个Session对象和一个管理器。另外,一个Session实例在跟管理器相关联的容器有一个唯一的ID。对于该ID有setIdgetId方法相关。

 

每次一个Session被调用的时候,都会调用access方法更新它的最后访问时间和次数

publicvoid access() {

       this.lastAccessedTime =this.thisAccessedTime;

       this.thisAccessedTime = System.currentTimeMillis();

        evaluateIfValid();

       accessCount++;

}

结束Session使用

publicvoid endAccess() {

       isNew = false;

       accessCount--;

    }

 

      在Manager创建Session的时候,会把新生成的SessionId放入Session实例,这时候session设置Id关联manager,然后触发相应事件监听

publicvoid setId(String id) {

       if ((this.id !=null) && (manager !=null))

           manager.remove(this);     //如果Id重复,直接覆盖

       this.id = id;

       if (manager !=null)

           manager.add(this);

        tellNew();

    }

 

getSession 外观模式

        Connector拼装StandardSession后,最后会传给servlet处理。出于安全和数据隐藏的原因,不会将一个StandardSession实例传直接递给servlet。而是返回外观类StandardSessionFacade

        StandardSession类的逻辑很复杂,有很多的属性和方法,例如引用Manager来管理Session;打印log;触发监听器等等。

但是传给Servlet,只需要显示一小部分信息,没必要全部暴露,所以创建一个对外的外观类来隐藏信息

public HttpSession getSession() {

       if (facade ==null){

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

               final StandardSession fsession =this;

               facade = (StandardSessionFacade)AccessController.doPrivileged(new PrivilegedAction(){

                   public Object run(){

                       return newStandardSessionFacade(fsession);

                    }

                });

            }else {

               facade = new StandardSessionFacade(this);

            }

        }

       return (facade);

}

 

超时-回收

      校验Session是否有效,accessCount>0正在被使用,视为有效;如果超时则视为无效。

publicboolean isValid() {

       if (this.expiring)return true;

       if (!this.isValid )return false;

       if (accessCount > 0)return true;

       if (maxInactiveInterval >= 0) {

           long timeNow = System.currentTimeMillis();

           int timeIdle = (int) ((timeNow -thisAccessedTime) / 1000L);

           if (timeIdle >= maxInactiveInterval)

                expire(true);

        }

       return (this.isValid);

    }

 

一个Session对象如果在由maxInactiveInterval变量的时间内没有access则视为无效,使用expire()来终结。

A 置可用性isValid为false,置使用关联accessCount为0

B 解除managerSession的关联

C 清除Session的属性;

D 触发事件监听器;

publicvoid expire(boolean notify) {

       if (expiring)return;         //置失效过了,直接返回

       synchronized (this) {

           if (manager ==null) return;

           expiring = true;

   

            Context context = (Context)manager.getContainer();

            Object listeners[] =context.getApplicationLifecycleListeners();

           if (notify && (listeners != null)) {

                HttpSessionEvent event =newHttpSessionEvent(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) { }

                }

            }

           accessCount = 0;         

            setValid(false);        

           if (manager !=null)    

               manager.remove(this);

           expiring = false;         //失效状态一前一后,防止一个Session重复expire


            String keys[] = (String[])attributes.keySet().toArray(EMPTY_ARRAY

           for (int i = 0; i < keys.length; i++)

               removeAttributeInternal(keys[i], notify);

        }

    }

 

 

 

 

 

你可能感兴趣的:(tomcat,session,manager,源代码)