Tomcat源码分析 -- Server的创建

2018-02-28  本文已影响39人  w1992wishes

本篇结构:

一、前言

前面已经介绍了Tomcat服务器的整体结构和启动过程,本篇将聚焦server.xml的解析,介绍Server的整个创建过程。

二、server的解析

要了解Server的创建,就需要回到前面关于Tomcat启动过程文章中介绍的Catalina中的load方法,在load方法中会解析conf/server.xml配置文件。

前面有提到,Tomcat是使用Digester解析server.xml的,Digester的解析规则是在Catalina类的createStartDigester方法中。

简单分析下该方法。

// 首先实例化一个Digester对象
Digester digester = new Digester();
// 设置为false表示解析xml时不需要进行DTD的规则校验  
digester.setValidating(false);
// 是否进行节点设置规则校验,如果xml中相应节点没有设置解析规则会在控制台显示提示信息 
digester.setRulesValidation(true);

2.1、创建Server实例

// Configure the actions we will be using
digester.addObjectCreate("Server",
                         "org.apache.catalina.core.StandardServer",
                         "className");
digester.addSetProperties("Server");
digester.addSetNext("Server",
                    "setServer",
                    "org.apache.catalina.Server");

默认的Server实现类是org.apache.catalina.core.StandardServer,也可以在server.xml的server标签上配置className指定自己的实现。创建Server实例后,然后设置Server相关属性,然后调用栈顶对象(即该Server)之后的对象(是前面通过push(this)放入的Catalina实例)的setServer方法,将server实例设置到Catalina对象中。

digester.addObjectCreate("Server/GlobalNamingResources",
                    "org.apache.catalina.deploy.NamingResourcesImpl");
digester.addSetProperties("Server/GlobalNamingResources");
digester.addSetNext("Server/GlobalNamingResources",
                    "setGlobalNamingResources",
                    "org.apache.catalina.deploy.NamingResourcesImpl");

然后以同样的规则创建J2EE企业命名上下文(JNDI),设置属性并将其设置到Server实例中。

digester.addObjectCreate("Server/Listener",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties("Server/Listener");
digester.addSetNext("Server/Listener",
                    "addLifecycleListener",
                    "org.apache.catalina.LifecycleListener");

接着为Server实例添加生命周期监听器,默认的server.xml中配置了5个生命周期监听器。

<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/>
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>

也可以自己写一个监听器,在server.xml中配置:

public class MyListener implements LifecycleListener {
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if (Lifecycle.START_EVENT.equals(event.getType())){
            test();
        }
    }

    private void test() {
        System.out.println("====================================");
        System.out.println("test test test");
        System.out.println("====================================");
    }
}

启动就能看到打印信息:

2.2、创建Service实例

digester.addObjectCreate("Server/Service",
                        "org.apache.catalina.core.StandardService",
                         "className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service",
                    "addService",
                    "org.apache.catalina.Service");

创建Service实例,默认是org.apache.catalina.core.StandardService,然后通过addService设置到Server实例中。

digester.addObjectCreate("Server/Service/Listener",
                        null, // MUST be specified in the element"
                        className");
digester.addSetProperties("Server/Service/Listener");
digester.addSetNext("Server/Service/Listener",
                    "addLifecycleListener",
                    "org.apache.catalina.LifecycleListener");

addLifecycleListener为Service增加生命周期监听器,默认情况下,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");

创建Executor实例,默认为org.apache.catalina.core.StandardThreadExecutor,并将其设置到Service实例中,默认情况下,未配置Executor。

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");

为Service实例添加Connector。在设置Connector相关属性时,会判断server.xml中是否指定了executor属性,如果是,会从Service中查找该名称的Executor设置到Connector中。同时,在创建Connector时,也会判断是否有sslImplementationName属性,如果有,设置到使用的协议中,为其指定一个SSL实现。

接着是一大段为Connector添加虚拟主机SSL配置相关的代码,不是很懂这些,就不列出了。

digester.addObjectCreate("Server/Service/Connector/Listener",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties("Server/Service/Connector/Listener");
digester.addSetNext("Server/Service/Connector/Listener",
                    "addLifecycleListener",
                    "org.apache.catalina.LifecycleListener");

为Connector添加监听器,默认未指定。

digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
                        null, // MUST be specified in the element
                        "className");
digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
                    "addUpgradeProtocol",
                    "org.apache.coyote.UpgradeProtocol");

为Connector添加添加升级协议。

// Add RuleSets for nested elements
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/"));
addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));

// When the 'engine' is found, set the parentClassLoader.
digester.addRule("Server/Service/Engine",
                 new SetParentClassLoaderRule(parentClassLoader));
addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");

最后这部分代码指定了Servlet容器相关的各级嵌套子节点的解析规则,它将每类子节点的解析封装为一个RuleSet包括GlobalNamingResources,Engine,Host,Context及Cluster的解析,这里重点关注Engine和Host的解析,它们的解析和Context密切相关。

三、Engine的解析

Engine的解析过程在EngineRuleSet类中。

3.1、创建Engine实例

//EngineRuleSet.addRuleInstances
digester.addObjectCreate(prefix + "Engine",
                        "org.apache.catalina.core.StandardEngine",
                        "className");
digester.addSetProperties(prefix + "Engine");
digester.addRule(prefix + "Engine",
                 new LifecycleListenerRule
                 ("org.apache.catalina.startup.EngineConfig",
                  "engineConfigClass"));
digester.addSetNext(prefix + "Engine",
                    "setContainer",
                    "org.apache.catalina.Engine");

创建Engine实例,默认是org.apache.catalina.core.StandardEngine,为其设置属性。接着会给Engine添加一个生命周期监听器,默认是org.apache.catalina.startup.EngineConfig,用于打印Engine启动和停止日志,然后将该Engine实例设置到Service中。

需要说明的是EngineConfig生命监听器不是在server.xml配置的,而是在创建Engine是默认添加的。

3.2、Engine集群配置

 //Cluster configuration start
digester.addObjectCreate(prefix + "Engine/Cluster",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Engine/Cluster");
digester.addSetNext(prefix + "Engine/Cluster",
                            "setCluster",

这段是为Engine创建集群配置,如需要,应在server.xml中江将Cluster标签注释打开,还未用过Tomcat的集群配置,相关内容就不详细介绍了。

3.3、为Engine添加生命周期监听器

digester.addObjectCreate(prefix + "Engine/Listener",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Engine/Listener");
digester.addSetNext(prefix + "Engine/Listener",
                    "addLifecycleListener",
                    "org.apache.catalina.LifecycleListener");

和EngineConfig不同,此处的生命周期监听器是在server.xml中配置的,默认未指定。

3.4、为Engine添加realm和valve

digester.addRuleSet(new RealmRuleSet(prefix + "Engine/"));
digester.addObjectCreate(prefix + "Engine/Valve",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Engine/Valve");
digester.addSetNext(prefix + "Engine/Valve",
                    "addValve",
                    "org.apache.catalina.Valve");

realm和tomcat安全相关,valve同tomcat处理请求方式相关。

四、Host的解析

Host的解析,是在HostRuleSet类的addRuleInstances方法中。

4.1、创建Host实例

digester.addObjectCreate(prefix + "Host",
                    "org.apache.catalina.core.StandardHost",
                         "className");
digester.addSetProperties(prefix + "Host");
digester.addRule(prefix + "Host",
                 new CopyParentClassLoaderRule());
digester.addRule(prefix + "Host",
                 new LifecycleListenerRule
                 ("org.apache.catalina.startup.HostConfig",
                  "hostConfigClass"));
digester.addSetNext(prefix + "Host",
                    "addChild",
                    "org.apache.catalina.Container");
digester.addCallMethod(prefix + "Host/Alias",
                       "addAlias", 0);

创建默认为org.apache.catalina.core.StandardHost的实例,并将host标签上的属性设置到host实例中。接着调用Host实例中的setParentClassLoader将Engine中getParentClassLoader方法的类加载设置进来。

同Engine一样,在创建Host时,默认会添加一个生命周期监听器HostConfig,该生命周期监听器比EngineConfig复杂得多,和web应用的加载有关,将在下一篇介绍。

此外,通过Alias,Host支持别名配置。

4.2、Host集群配置

//Cluster configuration start
digester.addObjectCreate(prefix + "Host/Cluster",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Host/Cluster");
digester.addSetNext(prefix + "Host/Cluster",
                    "setCluster",
                    "org.apache.catalina.Cluster");

可见,集群配置可以在Engine级别,也可在Host级别。

4.3、为Host添加生命周期监听器

digester.addObjectCreate(prefix + "Host/Listener",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Host/Listener");
digester.addSetNext(prefix + "Host/Listener",
                    "addLifecycleListener",
                    "org.apache.catalina.LifecycleListener");

此处的生命周期监听器是在server.xml中配置的,默认未指定。

4.4、为Host添加realm和valve

digester.addRuleSet(new RealmRuleSet(prefix + "Host/"));

digester.addObjectCreate(prefix + "Host/Valve",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Host/Valve");
digester.addSetNext(prefix + "Host/Valve",
                    "addValve",
                    "org.apache.catalina.Valve");

从配置文件中可以看到默认的Valve为AccessLogValve,用于在处理请求时记录访问日志。

<Host name="localhost" appBase="webapps"
      unpackWARs="true" autoDeploy="true">
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log" suffix=".txt"
           pattern="%h %l %u %t &quot;%r&quot; %s %b"/>
</Host>

五、Context的解析

最后看下Context的解析,在ContextRuleSet的addRuleInstances方法中。

首先应该明白,Context配置并非来源一处,在Tomcat的conf目录下和Web应用的META-INF目录下都有Context.xml配置文件,而且在server.xml中也可以配置Context标签。

多数情况并不需要在server.xml中配置Context,更多是由HostConfig自动扫描部署目录,以Context.xml文件为基础进行Context的创建,具体将在下篇介绍。

而这里是指根据server.xml配置的Context进行解析。

5.1、Context实例化

if (create) {
    digester.addObjectCreate(prefix + "Context",
            "org.apache.catalina.core.StandardContext", "className");
    digester.addSetProperties(prefix + "Context");
} else {
    digester.addRule(prefix + "Context", new SetContextPropertiesRule());
}

if (create) {
    digester.addRule(prefix + "Context",
                     new LifecycleListenerRule
                         ("org.apache.catalina.startup.ContextConfig",
                          "configClass"));
    digester.addSetNext(prefix + "Context",
                        "addChild",
                        "org.apache.catalina.Container");
}

Context的解析因create不同而不同。通过server.xml配置Context时,create为true,这时默认会创建org.apache.catalina.core.StandardContext的实例。

通过HostConfig自动创建Context时,create为false,此时仅解析子节点即可。

如果create为true,在创建Context同时,会为context实例添加一个生命周期监听器ContextConfig,用于详细配置Context,如解析web.xml等。

5.2、为Context添加生命周期监听器

digester.addObjectCreate(prefix + "Context/Listener",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Context/Listener");
digester.addSetNext(prefix + "Context/Listener",
                    "addLifecycleListener",
                    "org.apache.catalina.LifecycleListener");

默认未指定,可通过配置className属性指定。

5.3、为Context指定类加载器

digester.addObjectCreate(prefix + "Context/Loader",
                    "org.apache.catalina.loader.WebappLoader",
                    "className");
digester.addSetProperties(prefix + "Context/Loader");
digester.addSetNext(prefix + "Context/Loader",
                    "setLoader",
                    "org.apache.catalina.Loader");

创建WebappLoader实例,并将其设置到Context实例中。

5.4、为Context指定会话管理器

digester.addObjectCreate(prefix + "Context/Manager",
                         "org.apache.catalina.session.StandardManager",
                         "className");
digester.addSetProperties(prefix + "Context/Manager");
digester.addSetNext(prefix + "Context/Manager",
                    "setManager",
                    "org.apache.catalina.Manager");

digester.addObjectCreate(prefix + "Context/Manager/Store",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Context/Manager/Store");
digester.addSetNext(prefix + "Context/Manager/Store",
                    "setStore",
                    "org.apache.catalina.Store");

digester.addObjectCreate(prefix + "Context/Manager/SessionIdGenerator",
                         "org.apache.catalina.util.StandardSessionIdGenerator",
                         "className");
digester.addSetProperties(prefix + "Context/Manager/SessionIdGenerator");
digester.addSetNext(prefix + "Context/Manager/SessionIdGenerator",
                    "setSessionIdGenerator",
                    "org.apache.catalina.SessionIdGenerator");

默认的会话管理器为org.apache.catalina.session.StandardManager,同时为管理器指定会话存储方式和会话标识生成器。

5.5、为Context添加初始化参数

 digester.addObjectCreate(prefix + "Context/Parameter",
                 "org.apache.tomcat.util.descriptor.web.ApplicationParameter");
digester.addSetProperties(prefix + "Context/Parameter");
digester.addSetNext(prefix + "Context/Parameter",
            "addApplicationParameter",
            "org.apache.tomcat.util.descriptor.web.ApplicationParameter");

5.6、为Context添加安全配置和Web资源配置

digester.addRuleSet(new RealmRuleSet(prefix + "Context/"));

digester.addObjectCreate(prefix + "Context/Resources",
                     "org.apache.catalina.webresources.StandardRoot",
                     "className");
digester.addSetProperties(prefix + "Context/Resources");
digester.addSetNext(prefix + "Context/Resources",
                "setResources",
                "org.apache.catalina.WebResourceRoot");

digester.addObjectCreate(prefix + "Context/Resources/PreResources",
                     null, // MUST be specified in the element
                     "className");
digester.addSetProperties(prefix + "Context/Resources/PreResources");
digester.addSetNext(prefix + "Context/Resources/PreResources",
                "addPreResources",
                "org.apache.catalina.WebResourceSet");

digester.addObjectCreate(prefix + "Context/Resources/JarResources",
                     null, // MUST be specified in the element
                     "className");
digester.addSetProperties(prefix + "Context/Resources/JarResources");
digester.addSetNext(prefix + "Context/Resources/JarResources",
                "addJarResources",
                "org.apache.catalina.WebResourceSet");

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");

5.7、为Context添加Valve

digester.addObjectCreate(prefix + "Context/Valve",
                         null, // MUST be specified in the element
                         "className");
digester.addSetProperties(prefix + "Context/Valve");
digester.addSetNext(prefix + "Context/Valve",
                    "addValve",
                    "org.apache.catalina.Valve");

具体Valve可由className指定。

5.8、为Context添加守护资源配置

digester.addCallMethod(prefix + "Context/WatchedResource",
                       "addWatchedResource", 0);

digester.addCallMethod(prefix + "Context/WrapperLifecycle",
                       "addWrapperLifecycle", 0);

digester.addCallMethod(prefix + "Context/WrapperListener",
                       "addWrapperListener", 0);

digester.addObjectCreate(prefix + "Context/JarScanner",
                         "org.apache.tomcat.util.scan.StandardJarScanner",
                         "className");
digester.addSetProperties(prefix + "Context/JarScanner");
digester.addSetNext(prefix + "Context/JarScanner",
                    "setJarScanner",
                    "org.apache.tomcat.JarScanner");

digester.addObjectCreate(prefix + "Context/JarScanner/JarScanFilter",
                         "org.apache.tomcat.util.scan.StandardJarScanFilter",
                         "className");
digester.addSetProperties(prefix + "Context/JarScanner/JarScanFilter");
digester.addSetNext(prefix + "Context/JarScanner/JarScanFilter",
                    "setJarScanFilter",
                    "org.apache.tomcat.JarScanFilter");

WatchedResource标签可在Context.xml中找到,用于为Context添加监资源,当这些资源发生变化时,Web应用会被重新加载,默认为WEB-INF/web.xml。

WrapperListener标签用于为Context添加一个生命周期类,此类的实例不是添加到Context中,而是Context包含的Wrapper。

JarScanner标签为JarScanner指定一jar扫描器,JarScanFilter则为扫描器指定一个过滤器,只有符合条件的jar包才会被处理。

5.9、为Context添加Cookie处理器

digester.addObjectCreate(prefix + "Context/CookieProcessor",
                         "org.apache.tomcat.util.http.Rfc6265CookieProcessor",
                         "className");
digester.addSetProperties(prefix + "Context/CookieProcessor");
digester.addSetNext(prefix + "Context/CookieProcessor",
                    "setCookieProcessor",
                    "org.apache.tomcat.util.http.CookieProcessor");

六、总结

上面只是简单介绍了Server的创建,并没有把每个组件都讲得很清楚,我没打算了解那么细。

该篇结束后,下篇将对Servlet容器的两个核心功能进行分析:部署Web应用和将请求映射到具体的Servlet进行处理。

上一篇 下一篇

猜你喜欢

热点阅读