前面两篇简述了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:
- 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();
- }
- }
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();
}
}
- // Configure default manager if none was specified
- if (contextManager != null) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("standardContext.manager",
- contextManager.getClass().getName()));
- }
- setManager(contextManager);
- }
// Configure default manager if none was specified
if (contextManager != null) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("standardContext.manager",
contextManager.getClass().getName()));
}
setManager(contextManager);
}
- 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;
- }
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:
- 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;
- }
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方法:
- @Override
- public HttpSession getSession() {
- Session session = doGetSession(true);
- if (session == null) {
- return null;
- }
- return session.getSession();
- }
@Override
public HttpSession getSession() {
Session session = doGetSession(true);
if (session == null) {
return null;
}
return session.getSession();
}
- 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;
- }
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然后再创建,创建的过程也是先查询有没有,再创建:
- @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);
- }
@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的:
- /**
- * The collection of user data attributes associated with this Session.
- */
- 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:
- @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();
- }
- }
@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();
}
}
- 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");
- }
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中:
- @Override
- public ServletContext getServletContext() {
- return context.getServletContext();
- }
@Override
public ServletContext getServletContext() {
return context.getServletContext();
}
调用了context的getServletContext方法,继续追踪:
- /**
- * 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());
- }
/**
* 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方法:
- /**
- * 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);
- }
/**
* 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解析完成以后,后面去遍历启动,上面代码比较长,核心在这一部分:
- 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;
- }
- }
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三块内容到此为止,后续还会继续解读其他模块的源码。