上篇我们知道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 方法。