// org.apache.catalina.startup.HostConfig#lifecycleEvent /** * Process the START event for an associated Host. * * @param event The lifecycle event that has occurred */ @Override publicvoidlifecycleEvent(LifecycleEvent event){
// Identify the host we are associated with try { host = (Host) event.getLifecycle(); // 从StandardHost复制一些配置过来 if (host instanceof StandardHost) { setCopyXML(((StandardHost) host).isCopyXML()); setDeployXML(((StandardHost) host).isDeployXML()); setUnpackWARs(((StandardHost) host).isUnpackWARs()); setContextClass(((StandardHost) host).getContextClass()); } } catch (ClassCastException e) { log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); return; }
// 这里是listener提供的功能 // Process the event that has occurred if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) { check(); } elseif (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) { beforeStart(); } elseif (event.getType().equals(Lifecycle.START_EVENT)) { start(); } elseif (event.getType().equals(Lifecycle.STOP_EVENT)) { stop(); } }
// org.apache.catalina.core.StandardEngine#StandardEngine /** * Create a new StandardEngine component with the default basic Valve. */ publicStandardEngine(){
super(); pipeline.setBasic(new StandardEngineValve()); /* Set the jmvRoute using the system property jvmRoute */ try { setJvmRoute(System.getProperty("jvmRoute")); } catch(Exception ex) { log.warn(sm.getString("standardEngine.jvmRouteFail")); } // By default, the engine will hold the reloading thread // 这里修改了默认值 backgroundProcessorDelay = 10;
}
用jstack可以验证下,发现只有一条这个线程:
1 2 3 4 5
"ContainerBackgroundProcessor[StandardEngine[Catalina]]" #57 daemon prio=5 os_prio=31 tid=0x0000000118f72000 nid=0x7203 waiting on condition [0x000000017a0ba000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1357) at java.lang.Thread.run(Thread.java:748)
// org.apache.catalina.core.ContainerBase#threadStart /** * Start the background thread that will periodically check for * session timeouts. */ protectedvoidthreadStart(){
if (thread != null) return; // 注意虽然Host/Context/Wrapper也继承了ContainerBase,但是这个值都是默认的-1,不会创建线程 // StandardEngine修改了默认值,所以会有这个线程,线程内会调用子容器的backgroundProcess()方法 if (backgroundProcessorDelay <= 0) return;
/** * Check status of all webapps. */ protectedvoidcheck(){ // 是否开启自动部署 if (host.getAutoDeploy()) { // Check for resources modification to trigger redeployment DeployedApplication[] apps = deployed.values().toArray(new DeployedApplication[0]); for (int i = 0; i < apps.length; i++) { if (!isServiced(apps[i].name)) checkResources(apps[i], false); }
// Check for old versions of applications that can now be undeployed if (host.getUndeployOldVersions()) { checkUndeploy(); }
// Hotdeploy applications deployApps(); } }
// org.apache.catalina.startup.HostConfig#deployApps() /** * Deploy applications for any directories or WAR files that are found * in our "application root" directory. */ protectedvoiddeployApps(){
// Start our child containers, if not already started // 子容器启动(ServletWrapper) for (Container child : findChildren()) { if (!child.getState().isAvailable()) { child.start(); } }
// Start the Valves in our pipeline (including the basic), // if any // pipeline的初始化,会拉起valve的初始化 if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).start(); }
// Configure and call application event listeners // ServletContextListener的初始化,使用spring父子容器的话,这里会拉起父容器 // spring的listener: org.springframework.web.context.ContextLoaderListener if (ok) { if (!listenerStart()) { log.error(sm.getString("standardContext.listenerFail")); ok = false; } }
// Configure and call application filters // filter启动 if (ok) { if (!filterStart()) { log.error(sm.getString("standardContext.filterFail")); ok = false; } }
// Load and initialize all "load on startup" servlets // servlet启动,如果servlet设置了load-on-startup // 如果只是使用了spring mvc,一般就是个servlet,则是在这一步拉起来的 if (ok) { if (!loadOnStartup(findChildren())){ log.error(sm.getString("standardContext.servletFail")); ok = false; } }
Scan the web.xml files that apply to the web application and merge them using the rules defined in the spec. For the global web.xml files, where there is duplicate configuration, the most specific level wins. ie an application’s web.xml takes precedence over the host level or global web.xml file.
// org.apache.catalina.startup.ContextConfig#configureStart /** * Process a "contextConfig" event for this Context. */ protectedsynchronizedvoidconfigureStart(){ // Called from StandardContext.start()
// 处理Listener/Filter/Servlet上的@Resource注解 JSR250 if (!context.getIgnoreAnnotations()) { applicationAnnotationsConfig(); } if (ok) { validateSecurityRoles(); }
// Configure an authenticator if we need one if (ok) { authenticatorConfig(); }
// Make our application available if no problems were encountered if (ok) { context.setConfigured(true); } else { log.error(sm.getString("contextConfig.unavailable")); context.setConfigured(false); }
}
logEffectiveWebXml
Set to true if you want the effective web.xml used for a web application to be logged (at INFO level) when the application starts. The effective web.xml is the result of combining the application’s web.xml with any defaults configured by Tomcat and any web-fragment.xml files and annotations discovered. If not specified, the default value of false is used.
BEFORE_START_EVENT
调用start之前的钩子,主要是计算docBase
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// org.apache.catalina.startup.ContextConfig#beforeStart /** * Process a "before start" event for this Context. */ protectedsynchronizedvoidbeforeStart(){
// Restore docBase for management tools if (originalDocBase != null) { context.setDocBase(originalDocBase); }
CONFIGURE_STOP_EVENT
和configure start event对应,容器销毁时执行:
Removing children
Removing application parameters
Removing security constraints
Removing Ejbs
Removing environments
Removing errors pages
Removing filter defs
Removing filter maps
Removing local ejbs
Removing Mime mappings
Removing parameters
Removing resource env refs
Removing resource links
Removing resources
Removing security role
Removing servlet mappings
Removing welcome files
Removing wrapper lifecycles
Removing wrapper listeners
Remove (partially) folders and files created by antiLocking
Reset ServletContextInitializer scanning
AFTER_INIT_EVENT
如果存在conf/context.xml,则处理下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// org.apache.catalina.startup.ContextConfig#init /** * Process a "init" event for this Context. */ protectedvoidinit(){ // Called from StandardContext.init()
// org.apache.catalina.startup.ContextConfig#destroy /** * Process a "destroy" event for this Context. */ protectedsynchronizedvoiddestroy(){ // Called from StandardContext.destroy() if (log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.destroy")); }
// Skip clearing the work directory if Tomcat is being shutdown Server s = getServer(); if (s != null && !s.getState().isAvailable()) { return; }
// Changed to getWorkPath per Bugzilla 35819. if (context instanceof StandardContext) { String workDir = ((StandardContext) context).getWorkPath(); if (workDir != null) { ExpandWar.delete(new File(workDir)); } } }