1.1)StandardContext对象可能启动失败:这时available 设置为false,该属性表明StandardContext 对象是否可用;1.2)若启动成功:available=true,则表明StandardContext 对象配置正确;
3.1)StandardContext使用了一个事件监听器作为其配置器;(干货——StandardContext使用了一个事件监听器作为其配置器,参见下图中StandardContext.start()方法中lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null) 调用)3.2)当调用StandardContext.start()方法时,其中要做的一件事情是,触发一个生命周期事件。该事件调用监听器,对StandardContext实例进行配置;3.3)若配置成功,则监听器将 configured设置为true,否则StandardContext 实例拒绝启动,也就无法为http 请求提供服务了;
public StandardContext() { // org.apache.catalina.core.StandardContext.StandardContext().
super();
pipeline.setBasic(new StandardContextValve());
namingResources.setContainer(this);
}1.1)StandardContext 对象可能启动失败:这时available 设置为false,该属性表明StandardContext 对象是否可用;1.2)若启动成功:available=true,则表明StandardContext 对象配置正确,与其关联的子容器和组件都正确启动;
public synchronized void start() throws LifecycleException { //org.apache.catalina.core.StandardContext.start()方法
if (started)
throw new LifecycleException
(sm.getString("containerBase.alreadyStarted", logName()));
if (debug >= 1)
log("Starting");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
if (debug >= 1)
log("Processing start(), current available=" + getAvailable());
setAvailable(false);
setConfigured(false);
boolean ok = true;
// Add missing components as necessary
if (webappResources == null) { // (1) Required by Loader
if (debug >= 1)
log("Configuring default Resources");
try {
if ((docBase != null) && (docBase.endsWith(".war")))
setResources(new WARDirContext());
else
setResources(new FileDirContext());
} catch (IllegalArgumentException e) {
log("Error initializing resources: " + e.getMessage());
ok = false;
}
}
if (ok) {
if (!resourcesStart())
ok = false;
}
// Install DefaultContext configuration
if (!getOverride()) {
Container host = getParent();
if (host instanceof StandardHost) {
((StandardHost)host).installDefaultContext(this);
Container engine = host.getParent();
if( engine instanceof StandardEngine ) {
((StandardEngine)engine).installDefaultContext(this);
}
}
}
if (getLoader() == null) { // (2) Required by Manager
if (getPrivileged()) {
if (debug >= 1)
log("Configuring privileged default Loader");
setLoader(new WebappLoader(this.getClass().getClassLoader()));
} else {
if (debug >= 1)
log("Configuring non-privileged default Loader");
setLoader(new WebappLoader(getParentClassLoader()));
}
}
if (getManager() == null) { // (3) After prerequisites
if (debug >= 1)
log("Configuring default Manager");
setManager(new StandardManager());
}
// Initialize character set mapper
getCharsetMapper();
// Post work directory
postWorkDirectory();
// Reading the "catalina.useNaming" environment variable
String useNamingProperty = System.getProperty("catalina.useNaming");
if ((useNamingProperty != null)
&& (useNamingProperty.equals("false"))) {
useNaming = false;
}
if (ok && isUseNaming()) {
if (namingContextListener == null) {
namingContextListener = new NamingContextListener();
namingContextListener.setDebug(getDebug());
namingContextListener.setName(getNamingContextName());
addLifecycleListener(namingContextListener);
}
}
// Binding thread
ClassLoader oldCCL = bindThread();
// Standard container startup
if (debug >= 1)
log("Processing standard container startup");
if (ok) {
try {
addDefaultMapper(this.mapperClass);
started = true;
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
// Unbinding thread
unbindThread(oldCCL);
// Binding thread
oldCCL = bindThread();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our Mappers, if any
Mapper mappers[] = findMappers();
for (int i = 0; i < mappers.length; i++) {
if (mappers[i] instanceof Lifecycle)
((Lifecycle) mappers[i]).start();
}
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
// Start the Valves in our pipeline (including the basic),
// if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
} finally {
// Unbinding thread
unbindThread(oldCCL);
}
}
if (!getConfigured())
ok = false;
// We put the resources into the servlet context
if (ok)
getServletContext().setAttribute
(Globals.RESOURCES_ATTR, getResources());
// Binding thread
oldCCL = bindThread();
// Create context attributes that will be required
if (ok) {
if (debug >= 1)
log("Posting standard context attributes");
postWelcomeFiles();
}
// Configure and call application event listeners and filters
if (ok) {
if (!listenerStart())
ok = false;
}
if (ok) {
if (!filterStart())
ok = false;
}
// Unbinding thread
unbindThread(oldCCL);
// Set available status depending upon startup success
if (ok) {
if (debug >= 1)
log("Starting completed");
setAvailable(true);
} else {
log(sm.getString("standardContext.startFailed"));
try {
stop();
} catch (Throwable t) {
log(sm.getString("standardContext.startCleanup"), t);
}
setAvailable(false);
throw new LifecycleException(sm.getString("standardContext.startFailed"));
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
// Load and initialize all "load on startup" servlets
oldCCL = bindThread();
loadOnStartup(findChildren());
unbindThread(oldCCL);
}work1)触发 BEFORE_START 事件;public synchronized void start() throws LifecycleException { //org.apache.catalina.core.StandardContext.start()方法。 if (started) throw new LifecycleException (sm.getString("containerBase.alreadyStarted", logName())); if (debug >= 1) log("Starting"); // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);work2)将 availability 属性设置为false;work3)将 configured 属性设置为 false;if (debug >= 1) log("Processing start(), current available=" + getAvailable()); setAvailable(false); setConfigured(false); boolean ok = true;work4)配置资源;// Add missing components as necessary if (webappResources == null) { // (1) Required by Loader if (debug >= 1) log("Configuring default Resources"); try { if ((docBase != null) && (docBase.endsWith(".war"))) setResources(new WARDirContext()); else setResources(new FileDirContext()); } catch (IllegalArgumentException e) { log("Error initializing resources: " + e.getMessage()); ok = false; } } if (ok) { if (!resourcesStart()) ok = false; } // Install DefaultContext configuration if (!getOverride()) { Container host = getParent(); if (host instanceof StandardHost) { ((StandardHost)host).installDefaultContext(this); Container engine = host.getParent(); if( engine instanceof StandardEngine ) { ((StandardEngine)engine).installDefaultContext(this); } } }work5)设置载入器;if (getLoader() == null) { // (2) Required by Manager if (getPrivileged()) { if (debug >= 1) log("Configuring privileged default Loader"); setLoader(new WebappLoader(this.getClass().getClassLoader())); } else { if (debug >= 1) log("Configuring non-privileged default Loader"); setLoader(new WebappLoader(getParentClassLoader())); } }work6)设置Session 管理器;if (getManager() == null) { // (3) After prerequisites if (debug >= 1) log("Configuring default Manager"); setManager(new StandardManager()); }work7)初始化字符集映射器;// Initialize character set mapper getCharsetMapper(); // defined in start(). public CharsetMapper getCharsetMapper() { // Create a mapper the first time it is requested if (this.charsetMapper == null) { try { Class clazz = Class.forName(charsetMapperClass); this.charsetMapper = (CharsetMapper) clazz.newInstance(); } catch (Throwable t) { this.charsetMapper = new CharsetMapper(); } } return (this.charsetMapper); }work8)启动与该Context 容器相关联的组件;// Post work directory postWorkDirectory(); // Reading the "catalina.useNaming" environment variable String useNamingProperty = System.getProperty("catalina.useNaming"); if ((useNamingProperty != null) && (useNamingProperty.equals("false"))) { useNaming = false; } if (ok && isUseNaming()) { if (namingContextListener == null) { namingContextListener = new NamingContextListener(); namingContextListener.setDebug(getDebug()); namingContextListener.setName(getNamingContextName()); addLifecycleListener(namingContextListener); } } // Binding thread ClassLoader oldCCL = bindThread();work9)启动子容器;work10)启动管道对象;work11)启动Session 管理器;
work12)触发 START 事件,在这里监听器(ContextConfig 实例)会执行一些配置操作,若配置成功,ContextConfig 实例会将 StandardContext.configured 变量设置为 true;// Set available status depending upon startup success if (ok) { if (debug >= 1) log("Starting completed"); setAvailable(true); } else { log(sm.getString("standardContext.startFailed")); try { stop(); } catch (Throwable t) { log(sm.getString("standardContext.startCleanup"), t); } setAvailable(false); throw new LifecycleException(sm.getString("standardContext.startFailed")); }work13)检查 configured 属性的值,若为true,则调用 postWelcomePages()方法,载入那些需要在启动时就载入的子容器,即 Wrapper实例,将 availability属性设置为 true。若 configured 变量为false, 则调用stop() 方法;// Create context attributes that will be required if (ok) { // defined in start() method. if (debug >= 1) log("Posting standard context attributes"); postWelcomeFiles(); } private void postWelcomeFiles() { getServletContext().setAttribute("org.apache.catalina.WELCOME_FILES", welcomeFiles); }work14)触发 AFTER_START 事件;
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); // highlight line.
// Load and initialize all "load on startup" servlets
oldCCL = bindThread();
loadOnStartup(findChildren());
unbindThread(oldCCL);
public void invoke(Request request, Response response) throws IOException, ServletException {
// Wait if we are reloading
while (getPaused()) { // 返回 paused属性的值,当paused为true时,表明应用程序正在重载;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
;
}
}
// Normal request processing
if (swallowOutput) {
try {
SystemLogHandler.startCapture();
super.invoke(request, response);
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
log(log);
}
}
} else {
super.invoke(request, response);
}
}Attention)上述的StandardContext.invoke() 方法是tomcat 4中的实现,而在 tomcat5中,StandardContext 并没有提供 invoke()方法的实现,所以会执行 ContainerBase.invoke() 方法;而检查应用程序是否正在重载的工作移到了 StandardContextValve.invoke() 方法中;
1.1)StandardContext 实例的基础阀:是 org.apache.catalina.core.StandardContextValve 类的实例;1.2)StandardContextValve.invoke()方法要做的第一件事:是获取一个要处理 http 请求 的Wrapper 实例;
protected void addDefaultMapper(String mapperClass) { // org.apache.catalina.core.ContainerBase.addDefaultMapper() method.
// Do we need a default Mapper?
if (mapperClass == null)
return;
if (mappers.size() >= 1)
return;
// Instantiate and add a default Mapper
try {
Class clazz = Class.forName(mapperClass);
Mapper mapper = (Mapper) clazz.newInstance();
mapper.setProtocol("http");
addMapper(mapper);
} catch (Exception e) {
log(sm.getString("containerBase.addDefaultMapper", mapperClass),
e);
}
}public synchronized void start() throws LifecycleException {
// ......
if (ok) {
try {
addDefaultMapper(this.mapperClass);
started = true;
} //......
// private String mapperClass = "org.apache.catalina.core.StandardContextMapper";public void setContainer(Container container) { // org.apche.catalina.core.StandardContextMapper.setContainer().
if (!(container instanceof StandardContext))
throw new IllegalArgumentException
(sm.getString("httpContextMapper.container"));
context = (StandardContext) container;
}
public StandardContext() { // 而在StandardContext构造中调用setContainer().
super();
pipeline.setBasic(new StandardContextValve());
namingResources.setContainer(this);
}public Container map(Request request, boolean update) { // org.apache.catalina.core.StandardContextMapper.map().
int debug = context.getDebug();
// Has this request already been mapped?
if (update && (request.getWrapper() != null))
return (request.getWrapper());
// Identify the context-relative URI to be mapped
String contextPath =
((HttpServletRequest) request.getRequest()).getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI = requestURI.substring(contextPath.length());
// Apply the standard request URI mapping rules from the specification
Wrapper wrapper = null;
String servletPath = relativeURI;
String pathInfo = null;
String name = null;
// Rule 1 -- Exact Match
// Rule 2 -- Prefix Match
// Rule 3 -- Extension Match
// Rule 4 -- Default Match
// Update the Request (if requested) and return this Wrapper
if ((debug >= 1) && (wrapper != null))
context.log(" Mapped to servlet '" + wrapper.getName() +
"' with servlet path '" + servletPath +
"' and path info '" + pathInfo +
"' and update=" + update);
if (update) {
request.setWrapper(wrapper);
((HttpRequest) request).setServletPath(servletPath);
((HttpRequest) request).setPathInfo(pathInfo);
}
return (wrapper);
}
}public void invoke(Request request, Response response, ValveContext valveContext)
throws IOException, ServletException { <span style="font-family: Arial, Helvetica, sans-serif;">//org.apche.catalina.core.StandardContextValve.invoke().</span>
// .....
// Disallow any direct access to resources under WEB-INF or META-INF
HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
String contextPath = hreq.getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI =
requestURI.substring(contextPath.length()).toUpperCase();
//......
Context context = (Context) getContainer();
Wrapper wrapper = null;
try {
wrapper = (Wrapper) context.map(request, true); // highlight line.->ContainerBase.map().
} //......
// Ask this Wrapper to process this Request
response.setContext(context);
wrapper.invoke(request, response);
}public Container map(Request request, boolean update) {
// Select the Mapper we will use
Mapper mapper = findMapper(request.getRequest().getProtocol());
if (mapper == null)
return (null);
// Use this Mapper to perform this mapping
return (mapper.map(request, update));
}
public Mapper findMapper(String protocol) {
if (mapper != null)
return (mapper); // mapper == StandardContextMapper
else
synchronized (mappers) {
return ((Mapper) mappers.get(protocol));
}
}step1)会先标识出相对于Context的URL:step2)然后,它试图应用匹配规则找到一个适合的Wrapper实例;
// step1 begins.
public Container map(Request request, boolean update) { // org.apache.catalina.core.StandardContextMapper.map().
int debug = context.getDebug();
// Has this request already been mapped?
if (update && (request.getWrapper() != null))
return (request.getWrapper());
// Identify the context-relative URI to be mapped
String contextPath =
((HttpServletRequest) request.getRequest()).getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI = requestURI.substring(contextPath.length());
if (debug >= 1)
context.log("Mapping contextPath='" + contextPath +
"' with requestURI='" + requestURI +
"' and relativeURI='" + relativeURI + "'");
// step1 ends.
// step2 begins.
// Apply the standard request URI mapping rules from the specification
Wrapper wrapper = null;
String servletPath = relativeURI;
String pathInfo = null;
String name = null;
// Rule 1 -- Exact Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying exact match");
if (!(relativeURI.equals("/")))
name = context.findServletMapping(relativeURI);
if (name != null)
wrapper = (Wrapper) context.findChild(name); //highlight line.
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
// Rule 2 -- Prefix Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying prefix match");
servletPath = relativeURI;
while (true) {
name = context.findServletMapping(servletPath + "/*");
if (name != null)
wrapper = (Wrapper) context.findChild(name); // highlight line.
if (wrapper != null) {
pathInfo = relativeURI.substring(servletPath.length());
if (pathInfo.length() == 0)
pathInfo = null;
break;
}
int slash = servletPath.lastIndexOf('/');
if (slash < 0)
break;
servletPath = servletPath.substring(0, slash);
}
}
// Rule 3 -- Extension Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying extension match");
int slash = relativeURI.lastIndexOf('/');
if (slash >= 0) {
String last = relativeURI.substring(slash);
int period = last.lastIndexOf('.');
if (period >= 0) {
String pattern = "*" + last.substring(period);
name = context.findServletMapping(pattern); // highlight line.
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
}
}
// Rule 4 -- Default Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying default match");
name = context.findServletMapping("/");
if (name != null)
wrapper = (Wrapper) context.findChild(name); //highlight line.
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
// step2 ends.
// step3 begins.
// Update the Request (if requested) and return this Wrapper
if ((debug >= 1) && (wrapper != null))
context.log(" Mapped to servlet '" + wrapper.getName() +
"' with servlet path '" + servletPath +
"' and path info '" + pathInfo +
"' and update=" + update);
if (update) {
request.setWrapper(wrapper);
((HttpRequest) request).setServletPath(servletPath);
((HttpRequest) request).setPathInfo(pathInfo);
}
return (wrapper);
}public synchronized void reload() { //org.apache.catalina.core.StandardContext.reload().
// Validate our current component state
if (!started)
throw new IllegalStateException
(sm.getString("containerBase.notStarted", logName()));
// Make sure reloading is enabled
// if (!reloadable)
// throw new IllegalStateException
// (sm.getString("standardContext.notReloadable"));
log(sm.getString("standardContext.reloadingStarted"));
// Stop accepting requests temporarily
setPaused(true);
// Binding thread
ClassLoader oldCCL = bindThread();
// Shut down our session manager
if ((manager != null) && (manager instanceof Lifecycle)) {
try {
((Lifecycle) manager).stop();
} catch (LifecycleException e) {
log(sm.getString("standardContext.stoppingManager"), e);
}
}
// Shut down the current version of all active servlets
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
Wrapper wrapper = (Wrapper) children[i];
if (wrapper instanceof Lifecycle) {
try {
((Lifecycle) wrapper).stop();
} catch (LifecycleException e) {
log(sm.getString("standardContext.stoppingWrapper",
wrapper.getName()),
e);
}
}
}
// Shut down application event listeners
listenerStop();
// Clear all application-originated servlet context attributes
if (context != null)
context.clearAttributes();
// Shut down filters
filterStop();
if (isUseNaming()) {
// Start
namingContextListener.lifecycleEvent
(new LifecycleEvent(this, Lifecycle.STOP_EVENT));
}
// Binding thread
unbindThread(oldCCL);
// Shut down our application class loader
if ((loader != null) && (loader instanceof Lifecycle)) {
try {
((Lifecycle) loader).stop();
} catch (LifecycleException e) {
log(sm.getString("standardContext.stoppingLoader"), e);
}
}
// Binding thread
oldCCL = bindThread();
// Restart our application class loader
if ((loader != null) && (loader instanceof Lifecycle)) {
try {
((Lifecycle) loader).start();
} catch (LifecycleException e) {
log(sm.getString("standardContext.startingLoader"), e);
}
}
// Binding thread
unbindThread(oldCCL);
// Create and register the associated naming context, if internal
// naming is used
boolean ok = true;
if (isUseNaming()) {
// Start
namingContextListener.lifecycleEvent
(new LifecycleEvent(this, Lifecycle.START_EVENT));
}
// Binding thread
oldCCL = bindThread();
// Restart our application event listeners and filters
if (ok) {
if (!listenerStart()) {
log(sm.getString("standardContext.listenerStartFailed"));
ok = false;
}
}
if (ok) {
if (!filterStart()) {
log(sm.getString("standardContext.filterStartFailed"));
ok = false;
}
}
// Restore the "Welcome Files" and "Resources" context attributes
postResources();
postWelcomeFiles();
// Restart our currently defined servlets
for (int i = 0; i < children.length; i++) {
if (!ok)
break;
Wrapper wrapper = (Wrapper) children[i];
if (wrapper instanceof Lifecycle) {
try {
((Lifecycle) wrapper).start();
} catch (LifecycleException e) {
log(sm.getString("standardContext.startingWrapper",
wrapper.getName()),
e);
ok = false;
}
}
}
// Reinitialize all load on startup servlets
loadOnStartup(children);
// Restart our session manager (AFTER naming context recreated/bound)
if ((manager != null) && (manager instanceof Lifecycle)) {
try {
((Lifecycle) manager).start();
} catch (LifecycleException e) {
log(sm.getString("standardContext.startingManager"), e);
}
}
// Unbinding thread
unbindThread(oldCCL);
// Start accepting requests again
if (ok) {
log(sm.getString("standardContext.reloadingCompleted"));
} else {
setAvailable(false);
log(sm.getString("standardContext.reloadingFailed"));
}
setPaused(false);
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(Context.RELOAD_EVENT, null);
}public void setContainer(Container container) { // org.apache.catalina.loader.WebappLoader.setContainer().
// Deregister from the old Container (if any)
if ((this.container != null) && (this.container instanceof Context))
((Context) this.container).removePropertyChangeListener(this);
// Process this property change
Container oldContainer = this.container;
this.container = container;
support.firePropertyChange("container", oldContainer, this.container);
// Register with the new Container (if any)
if ((this.container != null) && (this.container instanceof Context)) {
setReloadable( ((Context) this.container).getReloadable() );
((Context) this.container).addPropertyChangeListener(this);
}
} public void setReloadable(boolean reloadable) { // org.apache.catalina.loader.WebappLoader.setContainer(). setReloadable()
// Process this property change
boolean oldReloadable = this.reloadable;
this.reloadable = reloadable;
support.firePropertyChange("reloadable",
new Boolean(oldReloadable),
new Boolean(this.reloadable));
// Start or stop our background thread if required
if (!started)
return;
if (!oldReloadable && this.reloadable)
threadStart();
else if (oldReloadable && !this.reloadable)
threadStop();
}A1)若 reloadable 从false 修改为true:则会调用 threadStart()方法;而threadStart()方法会启动一个专用的线程来不断地检查 WEB-INF 目录下的类和 JAR 文件的时间戳;A2)若reloadable 从 true 修改为false:则调用调用 threadStop() 方法;而threadStop() 方法则会终止该线程;
public synchronized void start() throws LifecycleException { //org.apache.catalina.core.ContainerBase.start() in tomcat5.
// Validate and update our current component state
if (started) {
log.info(sm.getString("containerBase.alreadyStarted", logName()));
return;
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
started = true;
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
getLogger();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Start our thread
threadStart(); //highlight line.
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}protected void threadStart() { //org.apache.catalina.core.ContainerBase.threadStart() in tomcat5.
if (thread != null)
return;
if (backgroundProcessorDelay <= 0)
return;
threadDone = false;
String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
thread = new Thread(new ContainerBackgroundProcessor(), threadName); //highlight line.
thread.setDaemon(true);
thread.start();
}protected class ContainerBackgroundProcessor implements Runnable { //org.apache.catalina.core.ContainerBase.ContainerBackroundProcessor class defined in tomcat 5, which is a inner class in ContainerBase
public void run() {
while (!threadDone) {
try {
Thread.sleep(backgroundProcessorDelay * 1000L);
} catch (InterruptedException e) {
;
}
if (!threadDone) {
Container parent = (Container) getMappingObject();
ClassLoader cl =
Thread.currentThread().getContextClassLoader();
if (parent.getLoader() != null) {
cl = parent.getLoader().getClassLoader();
}
processChildren(parent, cl); // highlight line.
}
}
}
protected void processChildren(Container container, ClassLoader cl) {
try {
if (container.getLoader() != null) {
Thread.currentThread().setContextClassLoader
(container.getLoader().getClassLoader());
}
container.backgroundProcess(); // highlight line.
} catch (Throwable t) {
log.error("Exception invoking periodic operation: ", t);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
Container[] children = container.findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i].getBackgroundProcessorDelay() <= 0) {
processChildren(children[i], cl);
}
}
}
}A1)ContainerBackgroundProcessor 类:实际上是 ContainerBase类的内部类;A2)在其run()方法中是一个while 循环,周期性地调用其 processChildren()方法:而processChildren()方法会调用其自身对象的 backgroundProcess()方法 和其 每个子容器的 processChildren()方法;A3)通过实现backgroundProcess()方法,ContainerBase类的子类可以使用一个专用线程来执行周期性任务;
5)tomcat5 中 StandardContext.backgroundProcess()方法的实现如下:
public void backgroundProcess() { //org.apache.catalina.core.ContainerBase.backgroundProcess() in tomcat 5.
if (!started)
return;
if (cluster != null) {
try {
cluster.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);
}
}
if (loader != null) {
try {
loader.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);
}
}
if (manager != null) {
try {
manager.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);
}
}
if (realm != null) {
try {
realm.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);
}
}
Valve current = pipeline.getFirst();
while (current != null) {
try {
current.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);
}
current = current.getNext();
}
lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
}
tomcat(12)org.apache.catalina.core.StandardContext源码剖析
原文:http://blog.csdn.net/pacosonswjtu/article/details/51444681