标签:
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