Servlet容器是tomcat的核心组件,所有基于jsp/servlet的Java web应用均需要依托servlet容器运行并对外提供服务。
tomcat本质上是一款servlet容器,因此Catalina是tomcat的核心,其它模块均为catalina提供支持。
Digester
Catalina使用digester解析xml配置文件,并创建应用服务器。
digester主要有对象栈、匹配模式和处理规则三部分。
对象栈保存各个节点对象。
digest用法:
解析用的代码:
public static void ts1() throws IOException, SAXException {
Digester digester=new Digester();
digester.setValidating(false);
digester.setRulesValidation(true);
digester.addObjectCreate("department",Department.class.getName());
digester.addSetProperties("department");//匹配到department节点时,设置对象属性.比如name,age等自定义属性自动装填。
digester.addObjectCreate("department/user",User.class.getName());
digester.addSetProperties("department/user");
digester.addSetNext("department/user","addUser",User.class.getName());
digester.addCallMethod("department/extension","putExtension",2);
digester.addCallParam("department/extension/property-name",0);
digester.addCallParam("department/extension/property-value",1);
Department d= (Department) digester.parse(TestMain.class.getResourceAsStream("/test.xml"));
System.out.println(d.getCode());
}
原文:
<?xml version="1.0" encoding="UTF-8" ?>
<department>
<user name="un1" code="uc1"></user>
<user name="un2" code="uc2"></user>
<extension>
<property-name>director</property-name>
<property-value>joke</property-value>
</extension>
</department>
Department和user是自定义的类,用于描述文件属性。
catalina类通过下面这个方法,创建了digester类。
protected Digester createStartDigester() {
long t1 = System.currentTimeMillis();
Digester digester = new Digester();
digester.setValidating(false);
digester.setRulesValidation(true);
Map<Class<?>, List<String>> fakeAttributes = new HashMap();
List<String> attrs = new ArrayList();
attrs.add("className");
fakeAttributes.put(Object.class, attrs);
digester.setFakeAttributes(fakeAttributes);
digester.setUseContextClassLoader(true);
digester.addObjectCreate("Server", "org.apache.catalina.core.StandardServer", "className");//创建server对象,如果有自定义className,则使用自定义的属性
digester.addSetProperties("Server");//装填属性
digester.addSetNext("Server", "setServer", "org.apache.catalina.Server");//设置到catalina类中
digester.addObjectCreate("Server/GlobalNamingResources", "org.apache.catalina.deploy.NamingResourcesImpl");
//创建Java EE企业命名上下文
digester.addSetProperties("Server/GlobalNamingResources");
digester.addSetNext("Server/GlobalNamingResources", "setGlobalNamingResources", "org.apache.catalina.deploy.NamingResourcesImpl");//将其设置到server实例中
//为server创建声明周期监听器
digester.addObjectCreate("Server/Listener", (String)null, "className");
digester.addSetProperties("Server/Listener");
digester.addSetNext("Server/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");
//className指定LifecycleListener,Catalina默认配置了5个监听器。
//Apr 在server初始化前加载APR库,并在server停止后销毁 //VersionLogger server初始化前打印操作系统,jvm以及服务器版本信息
//JreMemoryLeakPreventionListener server初始化前调用,以解决单例对象创建导致的jvm内存泄漏以及锁文件问题
//GlobalResourcesLifecycleListener server启动时,将JNDI资源注册为MBean管理
//ThreadLocalLeakPrevention 用于在context停止时重建Executor池中 的线程,避免导致内存泄漏
//构建service实例
digester.addObjectCreate("Server/Service", "org.apache.catalina.core.StandardService", "className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service", "addService", "org.apache.catalina.Service");//把实例添加到server中
//为service添加生命周期监听器,默认情况下,Catalina未指定service监听器
digester.addObjectCreate("Server/Service/Listener", (String)null, "className");
digester.addSetProperties("Server/Service/Listener");
digester.addSetNext("Server/Service/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");
//为service添加Executor
digester.addObjectCreate("Server/Service/Executor", "org.apache.catalina.core.StandardThreadExecutor", "className");
digester.addSetProperties("Server/Service/Executor");
digester.addSetNext("Server/Service/Executor", "addExecutor", "org.apache.catalina.Executor");
//为service添加connector,排除executor和sslImplementationName
digester.addRule("Server/Service/Connector", new ConnectorCreateRule());
digester.addRule("Server/Service/Connector", new SetAllPropertiesRule(new String[]{"executor", "sslImplementationName", "protocol"}));
digester.addSetNext("Server/Service/Connector", "addConnector", "org.apache.catalina.connector.Connector");
//为connector添加虚拟主机SSL配置
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig", "org.apache.tomcat.util.net.SSLHostConfig");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
digester.addSetNext("Server/Service/Connector/SSLHostConfig", "addSslHostConfig", "org.apache.tomcat.util.net.SSLHostConfig");
digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate", new CertificateCreateRule());
digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate", new SetAllPropertiesRule(new String[]{"type"}));
digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate", "addCertificate", "org.apache.tomcat.util.net.SSLHostConfigCertificate");
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf", "org.apache.tomcat.util.net.openssl.OpenSSLConf");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf", "setOpenSslConf", "org.apache.tomcat.util.net.openssl.OpenSSLConf");
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd", "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd", "addCmd", "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
//为connector添加生命周期监听器
digester.addObjectCreate("Server/Service/Connector/Listener", (String)null, "className");
digester.addSetProperties("Server/Service/Connector/Listener");
digester.addSetNext("Server/Service/Connector/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");
//为connector添加升级协议,用于支持HTTP/2
digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol", (String)null, "className");
digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
digester.addSetNext("Server/Service/Connector/UpgradeProtocol", "addUpgradeProtocol", "org.apache.coyote.UpgradeProtocol");
//添加子元素解析规则
digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
digester.addRuleSet(new EngineRuleSet("Server/Service/"));
digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
this.addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
digester.addRule("Server/Service/Engine", new SetParentClassLoaderRule(this.parentClassLoader));
this.addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
long t2 = System.currentTimeMillis();
if(log.isDebugEnabled()) {
log.debug("Digester for server.xml created " + (t2 - t1));
}
return digester;
}
Engine的解析
默认实现是StandardEngine,提供了默认配置EngineConfig用于打印engine的启动和停止日志。
public void addRuleInstances(Digester digester) {
digester.addObjectCreate(this.prefix + "Engine", "org.apache.catalina.core.StandardEngine", "className");
digester.addSetProperties(this.prefix + "Engine");
digester.addRule(this.prefix + "Engine", new LifecycleListenerRule("org.apache.catalina.startup.EngineConfig", "engineConfigClass"));
digester.addSetNext(this.prefix + "Engine", "setContainer", "org.apache.catalina.Engine");//添加到service实例中
//添加集群配置
digester.addObjectCreate(this.prefix + "Engine/Cluster", (String)null, "className");
digester.addSetProperties(this.prefix + "Engine/Cluster");
digester.addSetNext(this.prefix + "Engine/Cluster", "setCluster", "org.apache.catalina.Cluster");
//添加生命周期监听器
digester.addObjectCreate(this.prefix + "Engine/Listener", (String)null, "className");
digester.addSetProperties(this.prefix + "Engine/Listener");
digester.addSetNext(this.prefix + "Engine/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");
//添加安全配置
digester.addRuleSet(new RealmRuleSet(this.prefix + "Engine/"));
digester.addObjectCreate(this.prefix + "Engine/Valve", (String)null, "className");
digester.addSetProperties(this.prefix + "Engine/Valve");
digester.addSetNext(this.prefix + "Engine/Valve", "addValve", "org.apache.catalina.Valve");
}
host解析
public void addRuleInstances(Digester digester) {
digester.addObjectCreate(this.prefix + "Host", "org.apache.catalina.core.StandardHost", "className");
digester.addSetProperties(this.prefix + "Host");//注入属性
digester.addRule(this.prefix + "Host", new CopyParentClassLoaderRule());
digester.addRule(this.prefix + "Host", new LifecycleListenerRule("org.apache.catalina.startup.HostConfig", "hostConfigClass"));
//添加监听器
digester.addSetNext(this.prefix + "Host", "addChild", "org.apache.catalina.Container");
//把它添加到engine中
digester.addCallMethod(this.prefix + "Host/Alias", "addAlias", 0);//添加别名
//添加集群,为Host
digester.addObjectCreate(this.prefix + "Host/Cluster", (String)null, "className");
digester.addSetProperties(this.prefix + "Host/Cluster");
digester.addSetNext(this.prefix + "Host/Cluster", "setCluster", "org.apache.catalina.Cluster");
//添加生命周期管理
digester.addObjectCreate(this.prefix + "Host/Listener", (String)null, "className");
digester.addSetProperties(this.prefix + "Host/Listener");
digester.addSetNext(this.prefix + "Host/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");
//添加安全管理
digester.addRuleSet(new RealmRuleSet(this.prefix + "Host/"));
digester.addObjectCreate(this.prefix + "Host/Valve", (String)null, "className");
digester.addSetProperties(this.prefix + "Host/Valve");
digester.addSetNext(this.prefix + "Host/Valve", "addValve", "org.apache.catalina.Valve");
}
context解析
create为true时,表示通过server.xml配置context。
create为false时,通过HostConfig创建context。
public void addRuleInstances(Digester digester) {
if(this.create) {
digester.addObjectCreate(this.prefix + "Context", "org.apache.catalina.core.StandardContext", "className");
digester.addSetProperties(this.prefix + "Context");
} else {
digester.addRule(this.prefix + "Context", new SetContextPropertiesRule());
}
if(this.create) {
digester.addRule(this.prefix + "Context", new LifecycleListenerRule("org.apache.catalina.startup.ContextConfig", "configClass"));//生命周期监听器,用于详细配置context,如详细解析web.xml
digester.addSetNext(this.prefix + "Context", "addChild", "org.apache.catalina.Container");
}
digester.addObjectCreate(this.prefix + "Context/Listener", (String)null, "className");
digester.addSetProperties(this.prefix + "Context/Listener");
digester.addSetNext(this.prefix + "Context/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");
//指定生命周期监听器
digester.addObjectCreate(this.prefix + "Context/Loader", "org.apache.catalina.loader.WebappLoader", "className");
digester.addSetProperties(this.prefix + "Context/Loader");
digester.addSetNext(this.prefix + "Context/Loader", "setLoader", "org.apache.catalina.Loader");
//指定类加载器
digester.addObjectCreate(this.prefix + "Context/Manager", "org.apache.catalina.session.StandardManager", "className");
digester.addSetProperties(this.prefix + "Context/Manager");
digester.addSetNext(this.prefix + "Context/Manager", "setManager", "org.apache.catalina.Manager");
digester.addObjectCreate(this.prefix + "Context/Manager/Store", (String)null, "className");
digester.addSetProperties(this.prefix + "Context/Manager/Store");
digester.addSetNext(this.prefix + "Context/Manager/Store", "setStore", "org.apache.catalina.Store");
digester.addObjectCreate(this.prefix + "Context/Manager/SessionIdGenerator", "org.apache.catalina.util.StandardSessionIdGenerator", "className");
digester.addSetProperties(this.prefix + "Context/Manager/SessionIdGenerator");
digester.addSetNext(this.prefix + "Context/Manager/SessionIdGenerator", "setSessionIdGenerator", "org.apache.catalina.SessionIdGenerator");
//会话管理器
digester.addObjectCreate(this.prefix + "Context/Parameter", "org.apache.tomcat.util.descriptor.web.ApplicationParameter");
digester.addSetProperties(this.prefix + "Context/Parameter");
digester.addSetNext(this.prefix + "Context/Parameter", "addApplicationParameter", "org.apache.tomcat.util.descriptor.web.ApplicationParameter");
//添加初始化参数,这个会导致应用与tomcat紧耦合(一般很少更换服务容器,所以这个其实没什么影响)。
digester.addRuleSet(new RealmRuleSet(this.prefix + "Context/"));
digester.addObjectCreate(this.prefix + "Context/Resources", "org.apache.catalina.webresources.StandardRoot", "className");
digester.addSetProperties(this.prefix + "Context/Resources");
digester.addSetNext(this.prefix + "Context/Resources", "setResources", "org.apache.catalina.WebResourceRoot");
digester.addObjectCreate(this.prefix + "Context/Resources/PreResources", (String)null, "className");
digester.addSetProperties(this.prefix + "Context/Resources/PreResources");
digester.addSetNext(this.prefix + "Context/Resources/PreResources", "addPreResources", "org.apache.catalina.WebResourceSet");
digester.addObjectCreate(this.prefix + "Context/Resources/JarResources", (String)null, "className");
digester.addSetProperties(this.prefix + "Context/Resources/JarResources");
digester.addSetNext(this.prefix + "Context/Resources/JarResources", "addJarResources", "org.apache.catalina.WebResourceSet");
digester.addObjectCreate(this.prefix + "Context/Resources/PostResources", (String)null, "className");
digester.addSetProperties(this.prefix + "Context/Resources/PostResources");
digester.addSetNext(this.prefix + "Context/Resources/PostResources", "addPostResources", "org.apache.catalina.WebResourceSet");
//添加安全配置以及资源配置
digester.addObjectCreate(this.prefix + "Context/ResourceLink", "org.apache.tomcat.util.descriptor.web.ContextResourceLink");
digester.addSetProperties(this.prefix + "Context/ResourceLink");
digester.addRule(this.prefix + "Context/ResourceLink", new SetNextNamingRule("addResourceLink", "org.apache.tomcat.util.descriptor.web.ContextResourceLink"));
//添加资源链接,用于Java EE 命名服务
digester.addObjectCreate(this.prefix + "Context/Valve", (String)null, "className");
digester.addSetProperties(this.prefix + "Context/Valve");
digester.addSetNext(this.prefix + "Context/Valve", "addValve", "org.apache.catalina.Valve");
//添加拦截器Value
digester.addCallMethod(this.prefix + "Context/WatchedResource", "addWatchedResource", 0);//添加监视资源,这些资源发生变化时,web应用会重新加载,默认是web.xml
digester.addCallMethod(this.prefix + "Context/WrapperLifecycle", "addWrapperLifecycle", 0);//为context添加生命周期监听器,添加到context包含的wrapper上
digester.addCallMethod(this.prefix + "Context/WrapperListener", "addWrapperListener", 0);
digester.addObjectCreate(this.prefix + "Context/JarScanner", "org.apache.tomcat.util.scan.StandardJarScanner", "className");
digester.addSetProperties(this.prefix + "Context/JarScanner");
digester.addSetNext(this.prefix + "Context/JarScanner", "setJarScanner", "org.apache.tomcat.JarScanner");
digester.addObjectCreate(this.prefix + "Context/JarScanner/JarScanFilter", "org.apache.tomcat.util.scan.StandardJarScanFilter", "className");
digester.addSetProperties(this.prefix + "Context/JarScanner/JarScanFilter");
digester.addSetNext(this.prefix + "Context/JarScanner/JarScanFilter", "setJarScanFilter", "org.apache.tomcat.JarScanFilter");
//添加守护资源配置
digester.addObjectCreate(this.prefix + "Context/CookieProcessor", "org.apache.tomcat.util.http.Rfc6265CookieProcessor", "className");
digester.addSetProperties(this.prefix + "Context/CookieProcessor");
digester.addSetNext(this.prefix + "Context/CookieProcessor", "setCookieProcessor", "org.apache.tomcat.util.http.CookieProcessor");
}
//添加cookie管理器
web应用加载是server启动的核心处理过程,Catalina通过Standard host、hostconfig,standardcontext、contextConfig、standardWrapper这5个类完成对web应用的加载。
StandardHost加载web应用(即standardContext)的入口有2个,其中一个入口是由生命周期管理接口调用start方法启动,这是配置context元素在host元素内(解析server.xml时会创建context),这种方式不好用,因为每部署一个web应用,都需要在这来配置。
另一个入口是HostConfig自动扫描部署目录,创建context实例并启动。
StandardHost启动加载过程:
- 为host添加一个Value实现ErrorReportValue(也可以修改host的errorReportValueClass属性指定自己的错误处理Value),用于在服务器处理异常时输出错误页面。如果web.xml中没有添加错误处理页面,tomcat就会返回这个类生成的页面。
- 调用StandardHost父类ContainerBase的startInternal方法启动虚拟主机,处理分为以下几步
- 如果配置了集群组件Cluster,则启动
- 如果配置了安全组件Realm,则启动
- 启动子节点
- 启动Host持有的Pipeline组件
- 设置Host状态为Starting,此时会触发StartEvent事件,HostConfig监听这个事件,扫描Web部署目录,对于部署描述文件、WAR包等,会自动创建StandardContext实例,并添加到Context中。
- 启动Host层级的后台任务处理:Cluster后台任务、Realm后台任务处理、Pipeline中Value的后台任务处理。
HostConfig----它是一个LifecycleListener实现,由catalina添加到Host实例上。处理的生命周期事件包括Start_EVENT,PERIODIC_EVENT,STOP_EVENT。前两者与web应用部署密切相关,后者用于在Host停止时注销其对应的MBean。
START_EVENT事件
该事件在host启动时触发,完成服务器启动过程中的web应用部署(需要deployOnStartup为true,默认是true)。
· context描述文件部署:tomcat支持通过一个独立的Context描述文件来配置并启动web应用,配置方式如同server.xml中的context元素。配置文件的存储路径由host的xmlBase属性指定,默认为$CATALINA_BASE/conf/< Engine名称 >/host名称。
这个就会加载test/myApp目录下的应用,访问路径则path。
context的描述文件由hostConfig进行扫描和解析,而hostconfig会使用线程池同时解析多个context的xml文件。
而每个线程使用以下代码解析单个xml文件:
protected void deployDescriptor(ContextName cn, File contextXml) {
HostConfig.DeployedApplication deployedApp = new HostConfig.DeployedApplication(cn.getName(), true);
long startTime = 0L;
if(log.isInfoEnabled()) {
startTime = System.currentTimeMillis();
log.info(sm.getString("hostConfig.deployDescriptor", new Object[]{contextXml.getAbsolutePath()}));
}
Context context = null;
boolean isExternalWar = false;
boolean isExternal = false;
File expandedDocBase = null;
boolean var30 = false;
label870: {
boolean unpackWAR;
File warDocBase;
label871: {
try {
var30 = true;
FileInputStream fis = new FileInputStream(contextXml);
Throwable var11 = null;
try {
Object var12 = this.digesterLock;
synchronized(this.digesterLock) {
try {
context = (Context)this.digester.parse(fis);
} catch (Exception var49) {
log.error(sm.getString("hostConfig.deployDescriptor.error", new Object[]{contextXml.getAbsolutePath()}), var49);
} finally {
this.digester.reset();
if(context == null) {
context = new FailedContext();
}
}
}
Class<?> clazz = Class.forName(this.host.getConfigClass());
LifecycleListener listener = (LifecycleListener)clazz.newInstance();
((Context)context).addLifecycleListener(listener);
((Context)context).setConfigFile(contextXml.toURI().toURL());
((Context)context).setName(cn.getName());
((Context)context).setPath(cn.getPath());
((Context)context).setWebappVersion(cn.getVersion());
if(((Context)context).getDocBase() != null) {
File docBase = new File(((Context)context).getDocBase());
if(!docBase.isAbsolute()) {
docBase = new File(this.host.getAppBaseFile(), ((Context)context).getDocBase());
}
if(!docBase.getCanonicalPath().startsWith(this.host.getAppBaseFile().getAbsolutePath() + File.separator)) {
isExternal = true;
deployedApp.redeployResources.put(contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified()));
deployedApp.redeployResources.put(docBase.getAbsolutePath(), Long.valueOf(docBase.lastModified()));
if(docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) {
isExternalWar = true;
}
} else {
log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified", new Object[]{docBase}));
((Context)context).setDocBase((String)null);
}
}
this.host.addChild((Container)context);
} catch (Throwable var52) {
var11 = var52;
throw var52;
} finally {
if(fis != null) {
if(var11 != null) {
try {
fis.close();
} catch (Throwable var48) {
var11.addSuppressed(var48);
}
} else {
fis.close();
}
}
}
var30 = false;
break label871;
} catch (Throwable var54) {
ExceptionUtils.handleThrowable(var54);
log.error(sm.getString("hostConfig.deployDescriptor.error", new Object[]{contextXml.getAbsolutePath()}), var54);
var30 = false;
} finally {
if(var30) {
expandedDocBase = new File(this.host.getAppBaseFile(), cn.getBaseName());
if(((Context)context).getDocBase() != null && !((Context)context).getDocBase().toLowerCase(Locale.ENGLISH).endsWith(".war")) {
expandedDocBase = new File(((Context)context).getDocBase());
if(!expandedDocBase.isAbsolute()) {
expandedDocBase = new File(this.host.getAppBaseFile(), ((Context)context).getDocBase());
}
}
boolean unpackWAR = this.unpackWARs;
if(unpackWAR && context instanceof StandardContext) {
unpackWAR = ((StandardContext)context).getUnpackWAR();
}
if(isExternalWar) {
if(unpackWAR) {
deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified()));
this.addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), (Context)context);
} else {
this.addWatchedResources(deployedApp, (String)null, (Context)context);
}
} else {
if(!isExternal) {
File warDocBase = new File(expandedDocBase.getAbsolutePath() + ".war");
if(warDocBase.exists()) {
deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), Long.valueOf(warDocBase.lastModified()));
} else {
deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), Long.valueOf(0L));
}
}
if(unpackWAR) {
deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified()));
this.addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), (Context)context);
} else {
this.addWatchedResources(deployedApp, (String)null, (Context)context);
}
if(!isExternal) {
deployedApp.redeployResources.put(contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified()));
}
}
this.addGlobalRedeployResources(deployedApp);
}
}
expandedDocBase = new File(this.host.getAppBaseFile(), cn.getBaseName());
if(((Context)context).getDocBase() != null && !((Context)context).getDocBase().toLowerCase(Locale.ENGLISH).endsWith(".war")) {
expandedDocBase = new File(((Context)context).getDocBase());
if(!expandedDocBase.isAbsolute()) {
expandedDocBase = new File(this.host.getAppBaseFile(), ((Context)context).getDocBase());
}
}
unpackWAR = this.unpackWARs;
if(unpackWAR && context instanceof StandardContext) {
unpackWAR = ((StandardContext)context).getUnpackWAR();
}
if(isExternalWar) {
if(unpackWAR) {
deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified()));
this.addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), (Context)context);
} else {
this.addWatchedResources(deployedApp, (String)null, (Context)context);
}
} else {
if(!isExternal) {
warDocBase = new File(expandedDocBase.getAbsolutePath() + ".war");
if(warDocBase.exists()) {
deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), Long.valueOf(warDocBase.lastModified()));
} else {
deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), Long.valueOf(0L));
}
}
if(unpackWAR) {
deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified()));
this.addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), (Context)context);
} else {
this.addWatchedResources(deployedApp, (String)null, (Context)context);
}
if(!isExternal) {
deployedApp.redeployResources.put(contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified()));
}
}
this.addGlobalRedeployResources(deployedApp);
break label870;
}
expandedDocBase = new File(this.host.getAppBaseFile(), cn.getBaseName());
if(((Context)context).getDocBase() != null && !((Context)context).getDocBase().toLowerCase(Locale.ENGLISH).endsWith(".war")) {
expandedDocBase = new File(((Context)context).getDocBase());
if(!expandedDocBase.isAbsolute()) {
expandedDocBase = new File(this.host.getAppBaseFile(), ((Context)context).getDocBase());
}
}
unpackWAR = this.unpackWARs;
if(unpackWAR && context instanceof StandardContext) {
unpackWAR = ((StandardContext)context).getUnpackWAR();
}
if(isExternalWar) {
if(unpackWAR) {
deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified()));
this.addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), (Context)context);
} else {
this.addWatchedResources(deployedApp, (String)null, (Context)context);
}
} else {
if(!isExternal) {
warDocBase = new File(expandedDocBase.getAbsolutePath() + ".war");
if(warDocBase.exists()) {
deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), Long.valueOf(warDocBase.lastModified()));
} else {
deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), Long.valueOf(0L));
}
}
if(unpackWAR) {
deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified()));
this.addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), (Context)context);
} else {
this.addWatchedResources(deployedApp, (String)null, (Context)context);
}
if(!isExternal) {
deployedApp.redeployResources.put(contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified()));
}
}
this.addGlobalRedeployResources(deployedApp);
}
if(this.host.findChild(((Context)context).getName()) != null) {
this.deployed.put(((Context)context).getName(), deployedApp);
}
if(log.isInfoEnabled()) {
log.info(sm.getString("hostConfig.deployDescriptor.finished", new Object[]{contextXml.getAbsolutePath(), Long.valueOf(System.currentTimeMillis() - startTime)}));
}
}
ServletContext实现类为ApplicationContext。ApplicationFilterConfig负责Filter的实例化。FilterMap存储filter-mapping的配置。NamingResource存储web应用 的命名服务JNDI。
StandardContext的启动过程:
- 发布正在启动的JMX通知,这样可以添加NotificationList来监听web应用的启动
- 启动当前Context维护的JNDI资源
- 初始化当前Context使用的WebResourceRoot并启动,WebResourceRoot维护了所有的资源集合(class文件、jar包以及其它资源文件),主要用于类加载和按照路径查找资源。
- 创建web应用类加载器
- 如果当前Context使用JNDI,则为其添加NamingContextListener
- 启动web应用类加载器
- 启用安全组件Realm
- 发布Configure_Start_EVENT事件
- 启动context子节点
- 启用context维护的pipeline
- 创建会话管理器
- 将context的web资源集合添加到servletContext属性,属性名为org.apache.catalina.resources。
- 启动添加到当前Context的ServletContaionerInitializer
- 实例化应用监听器
- 检测未覆盖的HTTP方法的安全约束
- 启动会话管理器
- 实例化FilterConfig,Filter,并调用Filter的init初始化
- 启动后台定时任务
- 发布正在运行的JMX通知
- 设置context状态
ContextConfig是Context的生命周期监听器
context的创建途径:
- server.xml中有配置这个元素(这种方式一般不用,麻烦)
- HostConfig部署web应用时,解析web应用中的META-INF/context.xml创建(没有这个目录或文件也没关系,直接自动创建)
- Host部署Web应用时,解析$CATALINA_BASE/conf/Engine名/Host名 目录下的context文件创建(这种方式是为设置一些第二种方式设置不了的属性用的)
context的默认配置,优先使用conf目录下的,再次是conf/eng/host/目录下的,最后是context的configfile属性。
Before_start_event事件
在context启动之前触发,用于更新context的docBase属性和解决web目录锁的问题。
更新docBase是针对本身为war包的情况,修改docbase为解压后的文件目录
具体处理过程:
- 根据Host的appBase以及context的docbase计算docbase的绝对路径
- 如果docbase是war,则先解压,然后更新docbase为解压后的位置
- 如果docbase是一个不存在的目录,但是存在同名war包,则解压部署、
- 如果docbase是一个有效目录,当时存在同名war,如果允许覆盖,则重新解压
当antiResourceLocking属性为true时,tomcat会把web包或目录复制到临时文件目录。将context的docbase更新为临时目录下的web应用。
standardWrapper的start方法广播通知了它的状态变化,然后加载了所有启动时加载的servlet。
Tomcat通过Mapper维护请求链接与Host,context,wrapper等与contaioner的映射。同时通过MapperListener监听器监听所有的Host,context,wrapper组件,在相关组件启动、停止时注册或移除相关映射。
Connector接收到请求后,首先读取请求数据,然后调用CoyoteAdapter.service()完成请求处理。
根据connector的请求和响应对象创建Servlet请求,转换请求参数并完成映射,
请求URI解码,初始化请求的路径参数,检查URI是否合法,请求映射