浅读Tomcat源码(四)---session、servletContext、listener浅析

转载自:http://blog.csdn.net/qq_28241149/article/details/78465048

前面两篇简述了Tomcat的启动和请求处理,这篇我们来看一些平时使用中的细节用法


一.session

session对于web开发人员应该不会陌生了,session和cookie一个存储在服务端一个存储在客户端,我们来看下tomcat是如何实现session的。

建议大家认真读一下我在第一篇中发的几个链接,尤其是http://blog.csdn.net/beliefer/article/category/6154740,@泰山不老生的文章对session源码的解读还是很详尽的,这里我也用我自己的思路去整理一遍。


session的生成依赖于一个session的管理器,因此在Tomcat启动之初就生成了这个session管理器,我们来看下StandardContext的启动,我们在Tomcat启动的篇章已经讲述了四个容器依次启动的方式,而在context启动的时候会打开这个manager:


  1. Manager contextManager = null;  
  2. if (manager == null) {  
  3.     if (log.isDebugEnabled()) {  
  4.         log.debug(sm.getString("standardContext.cluster.noManager",  
  5.                 Boolean.valueOf((getCluster() != null)),  
  6.                 Boolean.valueOf(distributable)));  
  7.     }  
  8.     if ( (getCluster() != null) && distributable) {  
  9.         try {  
  10.             contextManager = getCluster().createManager(getName());  
  11.         } catch (Exception ex) {  
  12.             log.error("standardContext.clusterFail", ex);  
  13.             ok = false;  
  14.         }  
  15.     } else {  
  16.         contextManager = new StandardManager();  
  17.     }  
  18. }   
                Manager contextManager = null;
                if (manager == null) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("standardContext.cluster.noManager",
                                Boolean.valueOf((getCluster() != null)),
                                Boolean.valueOf(distributable)));
                    }
                    if ( (getCluster() != null) && distributable) {
                        try {
                            contextManager = getCluster().createManager(getName());
                        } catch (Exception ex) {
                            log.error("standardContext.clusterFail", ex);
                            ok = false;
                        }
                    } else {
                        contextManager = new StandardManager();
                    }
                } 
  1.                 // Configure default manager if none was specified  
  2.                 if (contextManager != null) {  
  3.                     if (log.isDebugEnabled()) {  
  4.                         log.debug(sm.getString("standardContext.manager",  
  5.                                 contextManager.getClass().getName()));  
  6.                     }  
  7.                     setManager(contextManager);  
  8.                 }  
                // Configure default manager if none was specified
                if (contextManager != null) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("standardContext.manager",
                                contextManager.getClass().getName()));
                    }
                    setManager(contextManager);
                }
  1. try {  
  2.     // Start manager  
  3.     if ((manager != null) && (manager instanceof Lifecycle)) {  
  4.         ((Lifecycle) getManager()).start();  
  5.     }  
  6.   
  7.     // Start ContainerBackgroundProcessor thread  
  8.     super.threadStart();  
  9. catch(Exception e) {  
  10.     log.error("Error manager.start()", e);  
  11.     ok = false;  
  12. }  
            try {
                // Start manager
                if ((manager != null) && (manager instanceof Lifecycle)) {
                    ((Lifecycle) getManager()).start();
                }
    
                // Start ContainerBackgroundProcessor thread
                super.threadStart();
            } catch(Exception e) {
                log.error("Error manager.start()", e);
                ok = false;
            }

以上是StandardContext的startInternal方法的两个片段,可以看到它先创建了manager对象,并赋值给了context内置的manager,最后去启动manager


manager的startInternal方法则调用了load方法,load调用doload:

  1. protected void doLoad() throws ClassNotFoundException, IOException {  
  2.     if (log.isDebugEnabled())  
  3.         log.debug("Start: Loading persisted sessions");  
  4.   
  5.     // Initialize our internal data structures  
  6.     sessions.clear();  
  7.   
  8.     // Open an input stream to the specified pathname, if any  
  9.     File file = file();  
  10.     if (file == null)  
  11.         return;  
  12.     if (log.isDebugEnabled())  
  13.         log.debug(sm.getString("standardManager.loading", pathname));  
  14.     FileInputStream fis = null;  
  15.     BufferedInputStream bis = null;  
  16.     ObjectInputStream ois = null;  
  17.     Loader loader = null;  
  18.     ClassLoader classLoader = null;  
  19.     try {  
  20.         fis = new FileInputStream(file.getAbsolutePath());  
  21.         bis = new BufferedInputStream(fis);  
  22.         if (container != null)  
  23.             loader = container.getLoader();  
  24.         if (loader != null)  
  25.             classLoader = loader.getClassLoader();  
  26.         if (classLoader != null) {  
  27.             if (log.isDebugEnabled())  
  28.                 log.debug("Creating custom object input stream for class loader ");  
  29.             ois = new CustomObjectInputStream(bis, classLoader);  
  30.         } else {  
  31.             if (log.isDebugEnabled())  
  32.                 log.debug("Creating standard object input stream");  
  33.             ois = new ObjectInputStream(bis);  
  34.         }  
  35.     } catch (FileNotFoundException e) {  
  36.         if (log.isDebugEnabled())  
  37.             log.debug("No persisted data file found");  
  38.         return;  
  39.     } catch (IOException e) {  
  40.         log.error(sm.getString("standardManager.loading.ioe", e), e);  
  41.         if (fis != null) {  
  42.             try {  
  43.                 fis.close();  
  44.             } catch (IOException f) {  
  45.                 // Ignore  
  46.             }  
  47.         }  
  48.         if (bis != null) {  
  49.             try {  
  50.                 bis.close();  
  51.             } catch (IOException f) {  
  52.                 // Ignore  
  53.             }  
  54.         }  
  55.         throw e;  
  56.     }  
    protected void doLoad() throws ClassNotFoundException, IOException {
        if (log.isDebugEnabled())
            log.debug("Start: Loading persisted sessions");

        // Initialize our internal data structures
        sessions.clear();

        // Open an input stream to the specified pathname, if any
        File file = file();
        if (file == null)
            return;
        if (log.isDebugEnabled())
            log.debug(sm.getString("standardManager.loading", pathname));
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        ObjectInputStream ois = null;
        Loader loader = null;
        ClassLoader classLoader = null;
        try {
            fis = new FileInputStream(file.getAbsolutePath());
            bis = new BufferedInputStream(fis);
            if (container != null)
                loader = container.getLoader();
            if (loader != null)
                classLoader = loader.getClassLoader();
            if (classLoader != null) {
                if (log.isDebugEnabled())
                    log.debug("Creating custom object input stream for class loader ");
                ois = new CustomObjectInputStream(bis, classLoader);
            } else {
                if (log.isDebugEnabled())
                    log.debug("Creating standard object input stream");
                ois = new ObjectInputStream(bis);
            }
        } catch (FileNotFoundException e) {
            if (log.isDebugEnabled())
                log.debug("No persisted data file found");
            return;
        } catch (IOException e) {
            log.error(sm.getString("standardManager.loading.ioe", e), e);
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException f) {
                    // Ignore
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException f) {
                    // Ignore
                }
            }
            throw e;
        }

通过文件输入流来初始化持久化的session,启动的流程大致是这样。


然后就是当调用的时候,我们可以看到org.apache.catalina.connector.Request类,里面的getSession方法:

  1. @Override  
  2. public HttpSession getSession() {  
  3.     Session session = doGetSession(true);  
  4.     if (session == null) {  
  5.         return null;  
  6.     }  
  7.    
  8.     return session.getSession();  
  9. }  
    @Override
    public HttpSession getSession() {
        Session session = doGetSession(true);
        if (session == null) {
            return null;
        }
     
        return session.getSession();
    }
  1. protected Session doGetSession(boolean create) {  
  2.   
  3.     // There cannot be a session if no context has been assigned yet  
  4.     if (context == null)  
  5.         return (null);  
  6.   
  7.     // Return the current session if it exists and is valid  
  8.     if ((session != null) && !session.isValid())  
  9.         session = null;  
  10.     if (session != null)  
  11.         return (session);  
  12.   
  13.     // Return the requested session if it exists and is valid  
  14.     Manager manager = null;  
  15.     if (context != null)  
  16.         manager = context.getManager();  
  17.     if (manager == null)  
  18.         return (null);      // Sessions are not supported  
  19.     if (requestedSessionId != null) {  
  20.         try {  
  21.             session = manager.findSession(requestedSessionId);  
  22.         } catch (IOException e) {  
  23.             session = null;  
  24.         }  
  25.         if ((session != null) && !session.isValid())  
  26.             session = null;  
  27.         if (session != null) {  
  28.             session.access();  
  29.             return (session);  
  30.         }  
  31.     }  
  32.   
  33.     // Create a new session if requested and the response is not committed  
  34.     if (!create)  
  35.         return (null);  
  36.     if ((context != null) && (response != null) &&  
  37.         context.getServletContext().getEffectiveSessionTrackingModes().  
  38.                 contains(SessionTrackingMode.COOKIE) &&  
  39.         response.getResponse().isCommitted()) {  
  40.         throw new IllegalStateException  
  41.           (sm.getString("coyoteRequest.sessionCreateCommitted"));  
  42.     }  
  43.   
  44.     // Attempt to reuse session id if one was submitted in a cookie  
  45.     // Do not reuse the session id if it is from a URL, to prevent possible  
  46.     // phishing attacks  
  47.     // Use the SSL session ID if one is present.   
  48.     if (("/".equals(context.getSessionCookiePath())   
  49.             && isRequestedSessionIdFromCookie()) || requestedSessionSSL ) {  
  50.         session = manager.createSession(getRequestedSessionId());  
  51.     } else {  
  52.         session = manager.createSession(null);  
  53.     }  
  54.   
  55.     // Creating a new session cookie based on that session  
  56.     if ((session != null) && (getContext() != null)  
  57.            && getContext().getServletContext().  
  58.                    getEffectiveSessionTrackingModes().contains(  
  59.                            SessionTrackingMode.COOKIE)) {  
  60.         Cookie cookie =  
  61.             ApplicationSessionCookieConfig.createSessionCookie(  
  62.                     context, session.getIdInternal(), isSecure());  
  63.           
  64.         response.addSessionCookieInternal(cookie);  
  65.     }  
  66.   
  67.     if (session == null) {  
  68.         return null;  
  69.     }  
  70.       
  71.     session.access();  
  72.     return session;  
  73. }  
    protected Session 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);

        // 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) {
                session.access();
                return (session);
            }
        }

        // Create a new session if requested and the response is not committed
        if (!create)
            return (null);
        if ((context != null) && (response != null) &&
            context.getServletContext().getEffectiveSessionTrackingModes().
                    contains(SessionTrackingMode.COOKIE) &&
            response.getResponse().isCommitted()) {
            throw new IllegalStateException
              (sm.getString("coyoteRequest.sessionCreateCommitted"));
        }

        // Attempt to reuse session id if one was submitted in a cookie
        // Do not reuse the session id if it is from a URL, to prevent possible
        // phishing attacks
        // Use the SSL session ID if one is present. 
        if (("/".equals(context.getSessionCookiePath()) 
                && isRequestedSessionIdFromCookie()) || requestedSessionSSL ) {
            session = manager.createSession(getRequestedSessionId());
        } else {
            session = manager.createSession(null);
        }

        // Creating a new session cookie based on that session
        if ((session != null) && (getContext() != null)
               && getContext().getServletContext().
                       getEffectiveSessionTrackingModes().contains(
                               SessionTrackingMode.COOKIE)) {
            Cookie cookie =
                ApplicationSessionCookieConfig.createSessionCookie(
                        context, session.getIdInternal(), isSecure());
            
            response.addSessionCookieInternal(cookie);
        }

        if (session == null) {
            return null;
        }
        
        session.access();
        return session;
    }

我们可以看到在doGetSession的时候还是先获取context,在上两篇已经讲到怎么把context传入每次的请求中了,然后启动时也将manager传入了context,因此在context中获取manager然后再创建,创建的过程也是先查询有没有,再创建:

  1. @Override  
  2. public Session createSession(String sessionId) {  
  3.       
  4.     if ((maxActiveSessions >= 0) &&  
  5.             (getActiveSessions() >= maxActiveSessions)) {  
  6.         rejectedSessions++;  
  7.         throw new IllegalStateException(  
  8.                 sm.getString("managerBase.createSession.ise"));  
  9.     }  
  10.       
  11.     // Recycle or create a Session instance  
  12.     Session session = createEmptySession();  
  13.   
  14.     // Initialize the properties of the new session and return it  
  15.     session.setNew(true);  
  16.     session.setValid(true);  
  17.     session.setCreationTime(System.currentTimeMillis());  
  18.     session.setMaxInactiveInterval(this.maxInactiveInterval);  
  19.     String id = sessionId;  
  20.     if (id == null) {  
  21.         id = generateSessionId();  
  22.     }  
  23.     session.setId(id);  
  24.     sessionCounter++;  
  25.   
  26.     SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);  
  27.     synchronized (sessionCreationTiming) {  
  28.         sessionCreationTiming.add(timing);  
  29.         sessionCreationTiming.poll();  
  30.     }  
  31.     return (session);  
  32.   
  33. }  
    @Override
    public Session createSession(String sessionId) {
        
        if ((maxActiveSessions >= 0) &&
                (getActiveSessions() >= maxActiveSessions)) {
            rejectedSessions++;
            throw new IllegalStateException(
                    sm.getString("managerBase.createSession.ise"));
        }
        
        // 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 id = sessionId;
        if (id == null) {
            id = generateSessionId();
        }
        session.setId(id);
        sessionCounter++;

        SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
        synchronized (sessionCreationTiming) {
            sessionCreationTiming.add(timing);
            sessionCreationTiming.poll();
        }
        return (session);

    }
而session的内部也是用一个map来储存attribute的:

  1. /** 
  2.      * The collection of user data attributes associated with this Session. 
  3.      */  
  4.     protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();  
/**
     * The collection of user data attributes associated with this Session.
     */
    protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();

之所以用concurrentHashMap,我们知道Tomcat的每个请求处理都在不同线程,因此需要用线性安全的map来存储。


最后与start对应的是manager的stop过程,其调用unload:

  1. @Override  
  2.  public void unload() throws IOException {  
  3.      if (SecurityUtil.isPackageProtectionEnabled()){  
  4.          try{  
  5.              AccessController.doPrivileged( new PrivilegedDoUnload() );  
  6.          } catch (PrivilegedActionException ex){  
  7.              Exception exception = ex.getException();  
  8.              if (exception instanceof IOException){  
  9.                  throw (IOException)exception;  
  10.              }  
  11.              if (log.isDebugEnabled())  
  12.                  log.debug("Unreported exception in unLoad() "  
  13.                      + exception);  
  14.          }  
  15.      } else {  
  16.          doUnload();  
  17.      }  
  18.  }  
   @Override
    public void unload() throws IOException {
        if (SecurityUtil.isPackageProtectionEnabled()){
            try{
                AccessController.doPrivileged( new PrivilegedDoUnload() );
            } catch (PrivilegedActionException ex){
                Exception exception = ex.getException();
                if (exception instanceof IOException){
                    throw (IOException)exception;
                }
                if (log.isDebugEnabled())
                    log.debug("Unreported exception in unLoad() "
                        + exception);
            }
        } else {
            doUnload();
        }
    }

  1. protected void doUnload() throws IOException {  
  2.   
  3.     if (log.isDebugEnabled())  
  4.         log.debug(sm.getString("standardManager.unloading.debug"));  
  5.   
  6.     if (sessions.isEmpty()) {  
  7.         log.debug(sm.getString("standardManager.unloading.nosessions"));  
  8.         return// nothing to do  
  9.     }  
  10.   
  11.     // Open an output stream to the specified pathname, if any  
  12.     File file = file();  
  13.     if (file == null)  
  14.         return;  
  15.     if (log.isDebugEnabled())  
  16.         log.debug(sm.getString("standardManager.unloading", pathname));  
  17.     FileOutputStream fos = null;  
  18.     ObjectOutputStream oos = null;  
  19.     try {  
  20.         fos = new FileOutputStream(file.getAbsolutePath());  
  21.         oos = new ObjectOutputStream(new BufferedOutputStream(fos));  
  22.     } catch (IOException e) {  
  23.         log.error(sm.getString("standardManager.unloading.ioe", e), e);  
  24.         if (fos != null) {  
  25.             try {  
  26.                 fos.close();  
  27.             } catch (IOException f) {  
  28.                 // Ignore  
  29.             }  
  30.         }  
  31.         throw e;  
  32.     }  
  33.   
  34.     // Write the number of active sessions, followed by the details  
  35.     ArrayList<StandardSession> list = new ArrayList<StandardSession>();  
  36.     synchronized (sessions) {  
  37.         if (log.isDebugEnabled())  
  38.             log.debug("Unloading " + sessions.size() + " sessions");  
  39.         try {  
  40.             oos.writeObject(new Integer(sessions.size()));  
  41.             Iterator<Session> elements = sessions.values().iterator();  
  42.             while (elements.hasNext()) {  
  43.                 StandardSession session =  
  44.                     (StandardSession) elements.next();  
  45.                 list.add(session);  
  46.                 session.passivate();  
  47.                 session.writeObjectData(oos);  
  48.             }  
  49.         } catch (IOException e) {  
  50.             log.error(sm.getString("standardManager.unloading.ioe", e), e);  
  51.             try {  
  52.                 oos.close();  
  53.             } catch (IOException f) {  
  54.                 // Ignore  
  55.             }  
  56.             throw e;  
  57.         }  
  58.     }  
  59.   
  60.     // Flush and close the output stream  
  61.     try {  
  62.         oos.flush();  
  63.     } finally {  
  64.         try {  
  65.             oos.close();  
  66.         } catch (IOException f) {  
  67.             // Ignore  
  68.         }  
  69.     }  
  70.   
  71.     // Expire all the sessions we just wrote  
  72.     if (log.isDebugEnabled())  
  73.         log.debug("Expiring " + list.size() + " persisted sessions");  
  74.     Iterator<StandardSession> expires = list.iterator();  
  75.     while (expires.hasNext()) {  
  76.         StandardSession session = expires.next();  
  77.         try {  
  78.             session.expire(false);  
  79.         } catch (Throwable t) {  
  80.             ExceptionUtils.handleThrowable(t);  
  81.         } finally {  
  82.             session.recycle();  
  83.         }  
  84.     }  
  85.   
  86.     if (log.isDebugEnabled())  
  87.         log.debug("Unloading complete");  
  88.   
  89. }  
    protected void doUnload() throws IOException {

        if (log.isDebugEnabled())
            log.debug(sm.getString("standardManager.unloading.debug"));

        if (sessions.isEmpty()) {
            log.debug(sm.getString("standardManager.unloading.nosessions"));
            return; // nothing to do
        }

        // Open an output stream to the specified pathname, if any
        File file = file();
        if (file == null)
            return;
        if (log.isDebugEnabled())
            log.debug(sm.getString("standardManager.unloading", pathname));
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        try {
            fos = new FileOutputStream(file.getAbsolutePath());
            oos = new ObjectOutputStream(new BufferedOutputStream(fos));
        } catch (IOException e) {
            log.error(sm.getString("standardManager.unloading.ioe", e), e);
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException f) {
                    // Ignore
                }
            }
            throw e;
        }

        // Write the number of active sessions, followed by the details
        ArrayList<StandardSession> list = new ArrayList<StandardSession>();
        synchronized (sessions) {
            if (log.isDebugEnabled())
                log.debug("Unloading " + sessions.size() + " sessions");
            try {
                oos.writeObject(new Integer(sessions.size()));
                Iterator<Session> elements = sessions.values().iterator();
                while (elements.hasNext()) {
                    StandardSession session =
                        (StandardSession) elements.next();
                    list.add(session);
                    session.passivate();
                    session.writeObjectData(oos);
                }
            } catch (IOException e) {
                log.error(sm.getString("standardManager.unloading.ioe", e), e);
                try {
                    oos.close();
                } catch (IOException f) {
                    // Ignore
                }
                throw e;
            }
        }

        // Flush and close the output stream
        try {
            oos.flush();
        } finally {
            try {
                oos.close();
            } catch (IOException f) {
                // Ignore
            }
        }

        // Expire all the sessions we just wrote
        if (log.isDebugEnabled())
            log.debug("Expiring " + list.size() + " persisted sessions");
        Iterator<StandardSession> expires = list.iterator();
        while (expires.hasNext()) {
            StandardSession session = expires.next();
            try {
                session.expire(false);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
            } finally {
                session.recycle();
            }
        }

        if (log.isDebugEnabled())
            log.debug("Unloading complete");

    }

将session的内容写入文件,和load过程相对应。



二.ServletContext

servletContext相对来说方便一点,我们直接看request中:

  1. @Override  
  2. public ServletContext getServletContext() {  
  3.     return context.getServletContext();  
  4.  }  
    @Override
    public ServletContext getServletContext() {
        return context.getServletContext();
     }
调用了context的getServletContext方法,继续追踪:

  1. /** 
  2.  * Return the servlet context for which this Context is a facade. 
  3.  */  
  4. @Override  
  5. public ServletContext getServletContext() {  
  6.   
  7.     if (context == null) {  
  8.         context = new ApplicationContext(this);  
  9.         if (altDDName != null)  
  10.             context.setAttribute(Globals.ALT_DD_ATTR,altDDName);  
  11.     }  
  12.     return (context.getFacade());  
  13.   
  14. }  
    /**
     * Return the servlet context for which this Context is a facade.
     */
    @Override
    public ServletContext getServletContext() {

        if (context == null) {
            context = new ApplicationContext(this);
            if (altDDName != null)
                context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
        }
        return (context.getFacade());

    }

典型的单例,我们之前讲到过,一个context容器对应一个web应用,而servletContext原本就是web应用的唯一存储容器,所以。。。不用解释了吧。



三.listener

servletContextListener是一个比较重要的概念,在web.xml中可以进行相应的配置,并监听项目的启动停止,其实他的实现过程也非常简单,在context的start过程中调用了listenerStart方法:

  1. /** 
  2.  * Configure the set of instantiated application event listeners 
  3.  * for this Context.  Return <code>true</code> if all listeners wre 
  4.  * initialized successfully, or <code>false</code> otherwise. 
  5.  */  
  6. public boolean listenerStart() {  
  7.   
  8.     if (log.isDebugEnabled())  
  9.         log.debug("Configuring application event listeners");  
  10.   
  11.     // Instantiate the required listeners  
  12.     String listeners[] = findApplicationListeners();  
  13.     Object results[] = new Object[listeners.length];  
  14.     boolean ok = true;  
  15.     for (int i = 0; i < results.length; i++) {  
  16.         if (getLogger().isDebugEnabled())  
  17.             getLogger().debug(" Configuring event listener class '" +  
  18.                 listeners[i] + "'");  
  19.         try {  
  20.             results[i] = instanceManager.newInstance(listeners[i]);  
  21.         } catch (Throwable t) {  
  22.             ExceptionUtils.handleThrowable(t);  
  23.             getLogger().error  
  24.                 (sm.getString("standardContext.applicationListener",  
  25.                               listeners[i]), t);  
  26.             ok = false;  
  27.         }  
  28.     }  
  29.     if (!ok) {  
  30.         getLogger().error(sm.getString("standardContext.applicationSkipped"));  
  31.         return (false);  
  32.     }  
  33.   
  34.     // Sort listeners in two arrays  
  35.     ArrayList<Object> eventListeners = new ArrayList<Object>();  
  36.     ArrayList<Object> lifecycleListeners = new ArrayList<Object>();  
  37.     for (int i = 0; i < results.length; i++) {  
  38.         if ((results[i] instanceof ServletContextAttributeListener)  
  39.             || (results[i] instanceof ServletRequestAttributeListener)  
  40.             || (results[i] instanceof ServletRequestListener)  
  41.             || (results[i] instanceof HttpSessionAttributeListener)) {  
  42.             eventListeners.add(results[i]);  
  43.         }  
  44.         if ((results[i] instanceof ServletContextListener)  
  45.             || (results[i] instanceof HttpSessionListener)) {  
  46.             lifecycleListeners.add(results[i]);  
  47.         }  
  48.     }  
  49.   
  50.     //Listeners may have been added by ServletContextInitializers.  Put them after the ones we know about.  
  51.     for (Object eventListener: getApplicationEventListeners()) {  
  52.         eventListeners.add(eventListener);  
  53.     }  
  54.     setApplicationEventListeners(eventListeners.toArray());  
  55.     for (Object lifecycleListener: getApplicationLifecycleListeners()) {  
  56.         lifecycleListeners.add(lifecycleListener);  
  57.     }  
  58.     setApplicationLifecycleListeners(lifecycleListeners.toArray());  
  59.   
  60.     // Send application start events  
  61.   
  62.     if (getLogger().isDebugEnabled())  
  63.         getLogger().debug("Sending application start events");  
  64.   
  65.     // Ensure context is not null  
  66.     getServletContext();  
  67.     context.setNewServletContextListenerAllowed(false);  
  68.       
  69.     Object instances[] = getApplicationLifecycleListeners();  
  70.     if (instances == null)  
  71.         return (ok);  
  72.     ServletContextEvent event =  
  73.       new ServletContextEvent(getServletContext());  
  74.     for (int i = 0; i < instances.length; i++) {  
  75.         if (instances[i] == null)  
  76.             continue;  
  77.         if (!(instances[i] instanceof ServletContextListener))  
  78.             continue;  
  79.         ServletContextListener listener =  
  80.             (ServletContextListener) instances[i];  
  81.         try {  
  82.             fireContainerEvent("beforeContextInitialized", listener);  
  83.             listener.contextInitialized(event);  
  84.             fireContainerEvent("afterContextInitialized", listener);  
  85.         } catch (Throwable t) {  
  86.             ExceptionUtils.handleThrowable(t);  
  87.             fireContainerEvent("afterContextInitialized", listener);  
  88.             getLogger().error  
  89.                 (sm.getString("standardContext.listenerStart",  
  90.                               instances[i].getClass().getName()), t);  
  91.             ok = false;  
  92.         }  
  93.     }  
  94.     return (ok);  
  95.   
  96. }  
    /**
     * Configure the set of instantiated application event listeners
     * for this Context.  Return <code>true</code> if all listeners wre
     * initialized successfully, or <code>false</code> otherwise.
     */
    public boolean listenerStart() {

        if (log.isDebugEnabled())
            log.debug("Configuring application event listeners");

        // Instantiate the required listeners
        String listeners[] = findApplicationListeners();
        Object results[] = new Object[listeners.length];
        boolean ok = true;
        for (int i = 0; i < results.length; i++) {
            if (getLogger().isDebugEnabled())
                getLogger().debug(" Configuring event listener class '" +
                    listeners[i] + "'");
            try {
                results[i] = instanceManager.newInstance(listeners[i]);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                getLogger().error
                    (sm.getString("standardContext.applicationListener",
                                  listeners[i]), t);
                ok = false;
            }
        }
        if (!ok) {
            getLogger().error(sm.getString("standardContext.applicationSkipped"));
            return (false);
        }

        // Sort listeners in two arrays
        ArrayList<Object> eventListeners = new ArrayList<Object>();
        ArrayList<Object> lifecycleListeners = new ArrayList<Object>();
        for (int i = 0; i < results.length; i++) {
            if ((results[i] instanceof ServletContextAttributeListener)
                || (results[i] instanceof ServletRequestAttributeListener)
                || (results[i] instanceof ServletRequestListener)
                || (results[i] instanceof HttpSessionAttributeListener)) {
                eventListeners.add(results[i]);
            }
            if ((results[i] instanceof ServletContextListener)
                || (results[i] instanceof HttpSessionListener)) {
                lifecycleListeners.add(results[i]);
            }
        }

        //Listeners may have been added by ServletContextInitializers.  Put them after the ones we know about.
        for (Object eventListener: getApplicationEventListeners()) {
            eventListeners.add(eventListener);
        }
        setApplicationEventListeners(eventListeners.toArray());
        for (Object lifecycleListener: getApplicationLifecycleListeners()) {
            lifecycleListeners.add(lifecycleListener);
        }
        setApplicationLifecycleListeners(lifecycleListeners.toArray());

        // Send application start events

        if (getLogger().isDebugEnabled())
            getLogger().debug("Sending application start events");

        // Ensure context is not null
        getServletContext();
        context.setNewServletContextListenerAllowed(false);
        
        Object instances[] = getApplicationLifecycleListeners();
        if (instances == null)
            return (ok);
        ServletContextEvent event =
          new ServletContextEvent(getServletContext());
        for (int i = 0; i < instances.length; i++) {
            if (instances[i] == null)
                continue;
            if (!(instances[i] instanceof ServletContextListener))
                continue;
            ServletContextListener listener =
                (ServletContextListener) instances[i];
            try {
                fireContainerEvent("beforeContextInitialized", listener);
                listener.contextInitialized(event);
                fireContainerEvent("afterContextInitialized", listener);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                fireContainerEvent("afterContextInitialized", listener);
                getLogger().error
                    (sm.getString("standardContext.listenerStart",
                                  instances[i].getClass().getName()), t);
                ok = false;
            }
        }
        return (ok);

    }
前面一大段将listener解析完成以后,后面去遍历启动,上面代码比较长,核心在这一部分:

  1. for (int i = 0; i < instances.length; i++) {  
  2.      if (instances[i] == null)  
  3.          continue;  
  4.      if (!(instances[i] instanceof ServletContextListener))  
  5.          continue;  
  6.      ServletContextListener listener =  
  7.          (ServletContextListener) instances[i];  
  8.      try {  
  9.          fireContainerEvent("beforeContextInitialized", listener);  
  10.          listener.contextInitialized(event);  
  11.          fireContainerEvent("afterContextInitialized", listener);  
  12.      } catch (Throwable t) {  
  13.          ExceptionUtils.handleThrowable(t);  
  14.          fireContainerEvent("afterContextInitialized", listener);  
  15.          getLogger().error  
  16.              (sm.getString("standardContext.listenerStart",  
  17.                            instances[i].getClass().getName()), t);  
  18.          ok = false;  
  19.      }  
  20.  }  
       for (int i = 0; i < instances.length; i++) {
            if (instances[i] == null)
                continue;
            if (!(instances[i] instanceof ServletContextListener))
                continue;
            ServletContextListener listener =
                (ServletContextListener) instances[i];
            try {
                fireContainerEvent("beforeContextInitialized", listener);
                listener.contextInitialized(event);
                fireContainerEvent("afterContextInitialized", listener);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                fireContainerEvent("afterContextInitialized", listener);
                getLogger().error
                    (sm.getString("standardContext.listenerStart",
                                  instances[i].getClass().getName()), t);
                ok = false;
            }
        }

好了,关于session、servletContext、listener三块内容到此为止,后续还会继续解读其他模块的源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值