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添加Executordigester.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和sslImplementationNamedigester.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/2digester.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);//添加别名//添加集群,为Hostdigester.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.xmldigester.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");
//添加拦截器Valuedigester.addCallMethod(this.prefix + "Context/WatchedResource", "addWatchedResource", 0);//添加监视资源,这些资源发生变化时,web应用会重新加载,默认是web.xmldigester.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启动加载过程:

  1. 为host添加一个Value实现ErrorReportValue(也可以修改host的errorReportValueClass属性指定自己的错误处理Value),用于在服务器处理异常时输出错误页面。如果web.xml中没有添加错误处理页面,tomcat就会返回这个类生成的页面。
  2. 调用StandardHost父类ContainerBase的startInternal方法启动虚拟主机,处理分为以下几步
    1. 如果配置了集群组件Cluster,则启动
    2. 如果配置了安全组件Realm,则启动
    3. 启动子节点
    4. 启动Host持有的Pipeline组件
    5. 设置Host状态为Starting,此时会触发StartEvent事件,HostConfig监听这个事件,扫描Web部署目录,对于部署描述文件、WAR包等,会自动创建StandardContext实例,并添加到Context中。
    6. 启动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的启动过程:

  1. 发布正在启动的JMX通知,这样可以添加NotificationList来监听web应用的启动
  2. 启动当前Context维护的JNDI资源
  3. 初始化当前Context使用的WebResourceRoot并启动,WebResourceRoot维护了所有的资源集合(class文件、jar包以及其它资源文件),主要用于类加载和按照路径查找资源。
  4. 创建web应用类加载器
  5. 如果当前Context使用JNDI,则为其添加NamingContextListener
  6. 启动web应用类加载器
  7. 启用安全组件Realm
  8. 发布Configure_Start_EVENT事件
  9. 启动context子节点
  10. 启用context维护的pipeline
  11. 创建会话管理器
  12. 将context的web资源集合添加到servletContext属性,属性名为org.apache.catalina.resources。
  13. 启动添加到当前Context的ServletContaionerInitializer
  14. 实例化应用监听器
  15. 检测未覆盖的HTTP方法的安全约束
  16. 启动会话管理器
  17. 实例化FilterConfig,Filter,并调用Filter的init初始化
  18. 启动后台定时任务
  19. 发布正在运行的JMX通知
  20. 设置context状态

ContextConfig是Context的生命周期监听器

context的创建途径:

  1. server.xml中有配置这个元素(这种方式一般不用,麻烦)
  2. HostConfig部署web应用时,解析web应用中的META-INF/context.xml创建(没有这个目录或文件也没关系,直接自动创建)
  3. 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为解压后的文件目录
具体处理过程:

  1. 根据Host的appBase以及context的docbase计算docbase的绝对路径
  2. 如果docbase是war,则先解压,然后更新docbase为解压后的位置
  3. 如果docbase是一个不存在的目录,但是存在同名war包,则解压部署、
  4. 如果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是否合法,请求映射

tomcat--catalina相关推荐

  1. 使用Tomcat Catalina进行Tomcat服务器虚拟目录设置

    最近使用Tomcat 的时候需要进行虚拟目录设置,上网查了一下说是使用Tomcat Catalina进行虚拟目录设置比较好,这样不用修改Tomcat其他相关配置,感觉这个方法很好,于是在下面试了一下, ...

  2. 解决Tomcat catalina.out 不断成长导致档案过大的问题

    解决Tomcat catalina.out 不断成长导致档案过大的问题 参考文章: (1)解决Tomcat catalina.out 不断成长导致档案过大的问题 (2)https://www.cnbl ...

  3. tomcat catalina.home和catalina.base区别(转)

    参考:http://desert3.iteye.com/blog/1356006 让我们看看这些目录那些可以被多个Tomcat实例公用,其实只有 bin 和 lib 目录,其它目录conf.logs. ...

  4. Tomcat catalina.bat 原理解析

    tomcat 的真正启动是在 catalina.bat 设置并启动的.startup.bat 只是找到catalina.bat 然后执行catalina.bat 来启动tomat的.下面我们来分析下c ...

  5. tomcat catalina localhost 没有项目_实用shell脚本--一键配置tomcat定期日志清理功能

    概述 日志文件包含了关于系统中发生的事件的有用信息,在排障过程中或者系统性能分析时经常被用到.对于忙碌的服务器,日志文件大小会增长极快,服务器会很快消耗磁盘空间,这成了个问题.除此之外,处理一个单个的 ...

  6. apache tomcat (catalina)查版本(solaris/unix)

    先进到tomcat的bin目录下(cd /tomcat目录/bin),在执行./version.sh https://blog.csdn.net/vv___/article/details/78653 ...

  7. Tomcat catalina.properties配置文件详解

    Tomcat的catalina.properties文件位于%CATALINA_HOME%/conf/目录下面,该文件主要配置tomcat的安全设置.类加载设置.不需要扫描的类设置.字符缓存设置四大块 ...

  8. tomcat catalina localhost 没有项目_Tomcat简介--01

    一.tomcat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache,Sun和其他一些公司及个人共同开 ...

  9. IDEA Tomcat Catalina Log出现乱码

    将tomcat – >conf -->logging.properties 这五处UTF-8改为GBK, IDEA的编码还是UTF-8不用动,问题解决

  10. linux 下清空tomcat catalina.out内容,释放磁盘空间

    2019独角兽企业重金招聘Python工程师标准>>> 转载于:https://my.oschina.net/likaixuan0/blog/3005918

最新文章

  1. [原]tornado源码分析系列(三)[网络层 IOLoop类]
  2. mysql启动错误1067进程意外终止的解决方法
  3. AFIO时钟何时开启
  4. shell的输入和输出
  5. 欢迎您参加_ADT技术培训营
  6. c++的STL--1概念通述
  7. linux ssd硬盘做缓存,linux系统中ssd当块设备缓存
  8. 在Node中基于Mongoose对MongoDB进行增删查改(CRUD)操作(一)
  9. 如何提高软件开发团队的协作效率
  10. “新元宇宙”奇科幻小说原创作品系列连载《地球人奇游天球记》第三回零点惊魂
  11. 如何为摇滚音乐选择吉他音箱,创作原创音乐
  12. 1.2. Container Overview
  13. 飞塔防火墙之ACL配置
  14. 最小生成树-普利姆和克鲁斯卡尔算法
  15. 手机遇到性能BUG怎么破?
  16. Rotten Tomatoes 电影数据分析
  17. CreateCompatibleDC(HDC hdc);
  18. java 批量执行 sql_JDBC批量执行SQL
  19. 图片聚类——k-means算法的python实现
  20. 备战一年,终于斩获腾讯T3,我坚信成功是可以复制的

热门文章

  1. Day2--使用ESP32双核、U8G2 OLED任务、任务以绝对频率运行、任务内存优化
  2. Android 组件化方案 JIMU 体验
  3. termux是等于linux终端,termux终端
  4. 整理10类Java毕设练手项目,献给帅帅的计算计专业毕业人
  5. js全屏和退出全屏代码
  6. mysql 大数据量查询总数 方式比较
  7. 程序员写代码要写注释吗?写你就输了
  8. 网络路由交换 -- 静态路由 和 缺省路由
  9. caffe accuracy 学习
  10. TMC429 - 三轴2相步进电机控制芯片