tomcat阅读第十二篇(tomcat组件之Context)
上篇我们知道deployApps方法,Context可以在这里创建,现在看下相关代码片段
protected void deployApps() { File appBase = host.getAppBaseFile(); File configBase = host.getConfigBaseFile(); String[] filteredAppPaths = filterAppPaths(appBase.list()); // Deploy XML descriptors from configBase deployDescriptors(configBase, configBase.list()); // Deploy WARs deployWARs(appBase, filteredAppPaths); // Deploy expanded folders deployDirectories(appBase, filteredAppPaths); }
protected void deployDirectory(ContextName cn, File dir) { …………. //或者由配置了Context.xml用Digester解析得到,如果Context标签没有指定className,默认也是org.apache.catalina.core.StandardContext context = (Context) digester.parse(xml); ……………….. //或者用反射创建context,context默认是org.apache.catalina.core.StandardContext context = (Context) Class.forName(contextClass).newInstance(); //host标签没有配置ConfigClass属性的话,默认是org.apache.catalina.startup.ContextConfig,这个是重点,解析配置信息的代码都在ContextConfig Class<?> clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); context.addLifecycleListener(listener); context.setName(cn.getName()); context.setPath(cn.getPath()); context.setWebappVersion(cn.getVersion()); context.setDocBase(cn.getBaseName()); //之前看过ContainerBase,addChild如果child是Container则调用Container的start方法,Context就是在这里启动的 host.addChild(context); …………………
所以现在看StandardContext,观察Context和StandardContext可以看到基本上都是一系列的get set方法,前面分析我们知道这些可以是Context标签的属性值,用Digester配置解析来赋值,跟之前的Container一样,Context的构造方法也是会添加basicvalve,跟请求相关的后面分析,注意这里没有指定backgroundProcessorDelay 的值,所以Context的 Child的backgroundProcess不会被执行.
public StandardContext() { super(); pipeline.setBasic(new StandardContextValve()); broadcaster = new NotificationBroadcasterSupport(); if (!Globals.STRICT_SERVLET_COMPLIANCE) { resourceOnlyServlets.add("jsp"); } }
上面添加看到context.addLifecycleListener(listener),上篇我们讲到HostConfig(LifeCycleListener),Host的主要逻辑是在HostConfig的事件回调方法里面来执行的,同样Context的主要逻辑也是在ContextConfig里面,稍后分析ContextConfig。
在Server.xml里面我们可以不用配置Context标签,上面deployApps方法会解析webapps里面的war、directory或者host里配置的ConfigBaseFile 属性指定的文件夹下配置的xml来创建【deployApps(webapps(war、directory)和ConfigBaseFile下的xml文件)】
也可以在Server.xml解析配置Context标签来创建Context,现在来看下Catalina的createStartDigester里面Context的部分,看源码可以知道跟Context相关的rule是ContextRuleSet 现在看下ContextRuleSet 的addRuleInstances 方法
public void addRuleInstances(Digester digester) { if (create) { //创建StandardContext对象 digester.addObjectCreate(prefix + "Context", "org.apache.catalina.core.StandardContext", "className"); //设置Context标签属性给StandardContext对象 digester.addSetProperties(prefix + "Context"); } else { digester.addRule(prefix + "Context", new SetContextPropertiesRule()); } if (create) { //创建ContextConfig对象 digester.addRule(prefix + "Context", new LifecycleListenerRule ("org.apache.catalina.startup.ContextConfig", "configClass")); //调用Host的addChild方法传入StandardContext digester.addSetNext(prefix + "Context", "addChild", "org.apache.catalina.Container"); } //解析到Listener标签,用className值通过反射创建Listener对象 digester.addObjectCreate(prefix + "Context/Listener", null, // MUST be specified in the element "className"); //设置Listener标签属性给Listener对象 digester.addSetProperties(prefix + "Context/Listener"); //调用Context的addLifecycleListener方法添加 digester.addSetNext(prefix + "Context/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener"); //解析到Loader标签,创建WebappLoader对象 digester.addObjectCreate(prefix + "Context/Loader", "org.apache.catalina.loader.WebappLoader", "className"); //设置Loader标签的属性给WebappLoader对象 digester.addSetProperties(prefix + "Context/Loader"); //调用Context对象setLoader方法,传入对象WebappLoader digester.addSetNext(prefix + "Context/Loader", "setLoader", "org.apache.catalina.Loader"); //解析到Manager,创建对象StandardManager digester.addObjectCreate(prefix + "Context/Manager", "org.apache.catalina.session.StandardManager", "className"); //设置Manager标签的属性给StandardManager digester.addSetProperties(prefix + "Context/Manager"); //调用Context对象的setManager 传入StandardManager digester.addSetNext(prefix + "Context/Manager", "setManager", "org.apache.catalina.Manager"); //解析到Manager/Store,通过className反射创建对象 digester.addObjectCreate(prefix + "Context/Manager/Store", null, // MUST be specified in the element "className"); //设置Store标签属性值给className创建的对象 digester.addSetProperties(prefix + "Context/Manager/Store"); //调用Manager对象的方法setStore,传入className创建的对象 digester.addSetNext(prefix + "Context/Manager/Store", "setStore", "org.apache.catalina.Store"); //解析到Manager/ SessionIdGenerator的时候创建对象StandardSessionIdGenerator,如果有指定了className属性,则用className的值反射创建 digester.addObjectCreate(prefix + "Context/Manager/SessionIdGenerator", "org.apache.catalina.util.StandardSessionIdGenerator", "className"); //设置SessionIdGenerator标签属性值给StandardSessionIdGenerator对象 digester.addSetProperties(prefix + "Context/Manager/SessionIdGenerator"); //调用Manager的setSessionIdGenerator方法,传入StandardSessionIdGenerator对象 digester.addSetNext(prefix + "Context/Manager/SessionIdGenerator", "setSessionIdGenerator", "org.apache.catalina.SessionIdGenerator"); //解析到Parameter标签的时候,创建对象ApplicationParameter digester.addObjectCreate(prefix + "Context/Parameter", "org.apache.tomcat.util.descriptor.web.ApplicationParameter"); //设置标签属性给ApplicationParameter对象 digester.addSetProperties(prefix + "Context/Parameter"); //调用Context的addApplicationParameter方法,传入ApplicationParameter对象 digester.addSetNext(prefix + "Context/Parameter", "addApplicationParameter", "org.apache.tomcat.util.descriptor.web.ApplicationParameter"); //Realm相关,后面再分析 digester.addRuleSet(new RealmRuleSet(prefix + "Context/")); //解析到Resources标签,创建对象StandardRoot digester.addObjectCreate(prefix + "Context/Resources", "org.apache.catalina.webresources. StandardRoot ", "className"); //设置Resources标签的属性值给StandardRoot对象 digester.addSetProperties(prefix + "Context/Resources"); //调用Context的setResources方法,传入WebResourceRoot digester.addSetNext(prefix + "Context/Resources", "setResources", "org.apache.catalina.WebResourceRoot"); //解析到标签Resources/PreResources,通过className指定的类反射创建对象 digester.addObjectCreate(prefix + "Context/Resources/PreResources", null, // MUST be specified in the element "className"); //设置PreResources标签属性的值给className创建的PreResources对象 digester.addSetProperties(prefix + "Context/Resources/PreResources"); //调用StandardRoot对象的addPreResources方法,传入WebResourceSet对象,PreResources标签className反射创建的对象 digester.addSetNext(prefix + "Context/Resources/PreResources", "addPreResources", "org.apache.catalina.WebResourceSet"); //解析到Resources/JarResources标签,创建对象通过className指定的类反射 digester.addObjectCreate(prefix + "Context/Resources/JarResources", null, // MUST be specified in the element "className"); //解析JarResources标签属性值设置给JarResources对象 digester.addSetProperties(prefix + "Context/Resources/JarResources"); //调用StandardRoot的方法addJarResources传入WebResourceSet对象 digester.addSetNext(prefix + "Context/Resources/JarResources", "addJarResources", "org.apache.catalina.WebResourceSet"); //同上Resource相关 digester.addObjectCreate(prefix + "Context/Resources/PostResources", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Context/Resources/PostResources"); digester.addSetNext(prefix + "Context/Resources/PostResources", "addPostResources", "org.apache.catalina.WebResourceSet"); digester.addObjectCreate(prefix + "Context/ResourceLink", "org.apache.tomcat.util.descriptor.web.ContextResourceLink"); digester.addSetProperties(prefix + "Context/ResourceLink"); digester.addRule(prefix + "Context/ResourceLink", new SetNextNamingRule("addResourceLink", "org.apache.tomcat.util.descriptor.web.ContextResourceLink")); //解析到valve,className属性值反射创建对象 digester.addObjectCreate(prefix + "Context/Valve", null, // MUST be specified in the element "className"); //设置valve标签属性值给对象valve digester.addSetProperties(prefix + "Context/Valve"); //调用StandardContext对象的addValve,传入创建的valve digester.addSetNext(prefix + "Context/Valve", "addValve", "org.apache.catalina.Valve"); //解析到WatchedResource,调用StandardContext对象的addWatchedResource方法,传入WatchedResource标签的context digester.addCallMethod(prefix + "Context/WatchedResource", "addWatchedResource", 0); //解析到WrapperLifecycle,调用StandardContext对象的addWrapperLifecycle方法,传入WrapperLifecycle标签的context digester.addCallMethod(prefix + "Context/WrapperLifecycle", "addWrapperLifecycle", 0); //解析到WrapperListener,调用StandardContext对象的addWrapperListener方法,传入WrapperListener标签的context digester.addCallMethod(prefix + "Context/WrapperListener", "addWrapperListener", 0); //解析到标签JarScanner,创建对象StandardJarScanner,如果指定了className,则用className属性反射创建对象 digester.addObjectCreate(prefix + "Context/JarScanner","org.apache.tomcat.util.scan.StandardJarScanner", "className"); //设置JarScanner标签属性给对象StandardJarScanner digester.addSetProperties(prefix + "Context/JarScanner"); //调用StandardContext的setJarScanner方法,传入StandardJarScanner digester.addSetNext(prefix + "Context/JarScanner", "setJarScanner", "org.apache.tomcat.JarScanner"); //解析到JarScanner/JarScanFilter,默认创建对象StandardJarScanFilter digester.addObjectCreate(prefix + "Context/JarScanner/JarScanFilter", "org.apache.tomcat.util.scan.StandardJarScanFilter", "className"); //设置标签JarScanFilter属性值给对象StandardJarScanFilter digester.addSetProperties(prefix + "Context/JarScanner/JarScanFilter"); //调用StandardJarScanner对象方法setJarScanFilter传入对象StandardJarScanFilter digester.addSetNext(prefix + "Context/JarScanner/JarScanFilter", "setJarScanFilter", "org.apache.tomcat.JarScanFilter"); //解析到CookieProcessor标签,默认创建对象Rfc6265CookieProcessor digester.addObjectCreate(prefix + "Context/CookieProcessor", "org.apache.tomcat.util.http.Rfc6265CookieProcessor", "className"); //设置标签CookieProcessor属性值给对象Rfc6265CookieProcessor digester.addSetProperties(prefix + "Context/CookieProcessor"); //调用StandardContext对象的setCookieProcessor 方法,传入Rfc6265CookieProcessor digester.addSetNext(prefix + "Context/CookieProcessor", "setCookieProcessor", "org.apache.tomcat.util.http.CookieProcessor"); }
这上面有很多我们新的类,主流程分析过后,可以慢慢再回来看这些类,这些每个类都代表了tomcat的特殊功能。还有跟Context的一个相关的rule NamingRuleSet,这个以后可以分析。StandardContext的XXXXInternal方法等分析完了ContextConfig再来分析,因为解析一些配置信息都算是在ContextConfig完成。
现在看Context的LifecycleListener ContextConfig,既然是LifecycleListener,就主要看lifecycleEvent,然后看各个回调方法
public void lifecycleEvent(LifecycleEvent event) { try { context = (Context) event.getLifecycle(); } catch (ClassCastException e) { log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e); return; } if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { //一般在beforestart,start之间触发CONFIGURE_START,调用configureStart configureStart(); }else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) { //startInternal调用之前触发BEFORE_START事件,调用beforeStart beforeStart(); }else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) { if (originalDocBase != null) { context.setDocBase(originalDocBase); } }else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) { //一般在stop,afterstop之间触发CONFIGURE_STOP,调用configureStop configureStop(); }else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) { //initInternal调用完后触发AFTER_INIT事件,调用init init(); }else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) { //destroyInternal调用完后触发AFTER_DESTROY,调用destroy destroy(); } }
BEFORE_START_EVENT事件触发,beforeStart方法:
protected synchronized void beforeStart() { try { //处理docBase,当war的时候,解压war然后重新计算docBase fixDocBase(); } catch (IOException e) { log.error(sm.getString( "contextConfig.fixDocBase", context.getName()), e); } //如果Context的属性AntiResourceLocking为true,则会copy docBasefile到 antiLockingDocBase[c:\\user\temp123docBasefile(syste的temp文件夹+ count++ +docbaseFile)] antiLocking(); }
CONFIGURE_START_EVENT事件触发,configureStart方法(单独分析):
protected synchronized void configureStart() { ……… //解析web相关的配置,这个具体分析 webConfig(); if (!context.getIgnoreAnnotations()) { //解析annotation,关于servlet、filter和listener applicationAnnotationsConfig(); } if (ok) { //解析Security相关配置 validateSecurityRoles(); } if (ok) { //解析authenticator相关配置 authenticatorConfig(); } …………… if (ok) { //设置配置完成true context.setConfigured(true); } else { log.error(sm.getString("contextConfig.unavailable")); context.setConfigured(false); } }
CONFIGURE_STOP_EVENT事件触发configureStop方法:
看代码可以发现stop方法里面都是context remove相关元素
AFTER_INIT_EVENT事件触发init方法(单独分析):
protected void init() { //创建解析Context.xml的Digester Digester contextDigester = createContextDigester(); contextDigester.getParser(); if (log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.init")); } context.setConfigured(false); ok = true; //解析Context,单独分析 contextConfig(contextDigester); }
AFTER_DESTROY_EVENT事件触发destroy方法:
protected synchronized void destroy() { if (log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.destroy")); } //如果tomcat shutdown的话,不用处理 Server s = getServer(); if (s != null && !s.getState().isAvailable()) { return; } // Changed to getWorkPath per Bugzilla 35819.// //删除workDir,workDir是在StandardContext的startInternal创建的,默认是 CatalinaHomefile\work\enginename\hostname\basename(用-替代分隔符的),如果host配置了workDir那么workDir是CatalinaHomefile \workDir\basename(用-替代分隔符的) if (context instanceof StandardContext) { String workDir = ((StandardContext) context).getWorkPath(); if (workDir != null) { ExpandWar.delete(new File(workDir)); } } }
下篇分析configureStart 方法。