文章目录
- 1. ContextConfig的基本流程
- 2. ContextConfig的核心功能
- 2.1 web-fragment.xml知识
- 2.2 ServletContainerInitializers的实现类
- 2.3 web.xml文件加载的细节
1. ContextConfig的基本流程
同HostConfig一样,ContextConfig
也是在初始化阶段由Digester
解析server.xml
的时候添加到StandardContext
上的监听器,在后续的启动阶段,会触发调用这个之前创建的监听器:
初始化期间完成注册流程:
load()
->Digester digester = createStartDigester();
->digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
->ruleSet.addRuleInstances(this);
-> digester.addRule(prefix + "Context",new LifecycleListenerRule("org.apache.catalina.startup.ContextConfig","configClass"));
->完成注册
ContextConfig 实现了LifecycleListener,就是一个监听器的实例:
public class ContextConfig implements LifecycleListener{public void lifecycleEvent(LifecycleEvent event){....do many things here!}}
digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
digester.addRule(prefix + "Context",new LifecycleListenerRule("org.apache.catalina.startup.ContextConfig","configClass"));
触发解析的流程,位于启动流程内:
startInternal()
->fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
-> for (LifecycleListener listener : lifecycleListeners) {listener.lifecycleEvent(event);}
->ContextConfig实例的fireLifecycleEvent()
-> if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {configureStart(); }
调用 listener.lifecycleEvent(event);时,注意event=start
参见入参的源头代码: fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT
, null);
2. ContextConfig的核心功能
ContextConfig
主要是处理web应用的配置文件:
org.apache.catalina.startup.ContextConfig {public void lifecycleEvent(LifecycleEvent event){if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {configureStart();} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {beforeStart();} else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {if (originalDocBase !&#61; null) {context.setDocBase(originalDocBase);}} ...}protected synchronized void configureStart() {webConfig();}protected void webConfig() {WebXmlParser webXmlParser &#61; new WebXmlParser(context.getXmlNamespaceAware(),context.getXmlValidation(), context.getXmlBlockExternal());Set<WebXml> defaults &#61; new HashSet<>();defaults.add(getDefaultWebXmlFragment(webXmlParser));WebXml webXml &#61; createWebXml(); InputSource contextWebXml &#61; getContextWebXmlSource();if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {ok &#61; false;}Map<String,WebXml> fragments &#61; processJarsForWebFragments(webXml, webXmlParser);Set<WebXml> orderedFragments &#61; null;orderedFragments &#61;WebXml.orderWebFragments(webXml, fragments, sContext);if (ok) {processServletContainerInitializers();}if (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {processClasses(webXml, orderedFragments);}if (!webXml.isMetadataComplete()) {if (ok) {ok &#61; webXml.merge(orderedFragments);}webXml.merge(defaults);if (ok) {convertJsps(webXml);}if (ok) {configureContext(webXml);}}
1、扫描/META-INF/lib/目录下的jar文件&#xff0c;如果在META-INF下含有web-fragment.xml文件&#xff0c;解析它&#xff1b;
2、确定确定这些xml片段的顺序
3、处理ServletContainerInitializers的实现类
4、将应用中的web.xml与orderedFragments进行合并&#xff0c;合并在WebXml类的merge方法中实现
5、将应用中的web.xml与全局的web.xml文件&#xff08;conf/web.xml和web.xml.default&#xff09;进行合并
6、用合并好的WebXml来配置Context&#xff0c;这一步在处理servlet时&#xff0c;会为每个servlet创建一个wrapper&#xff0c;并调用addChild将每个wrapper作为context子容器&#xff0c;后续分析
2.1 web-fragment.xml知识
servlet 3.0
可以将配置文件分散在多个jar包里面&#xff0c;而且还可以定义这些配置文件的顺序。分为绝对顺序和相对顺序&#xff0c;绝对顺序是通过absolute-ordering
标签定义的&#xff1a;
<web-app><name>...</name><absolute-ordering><name>fragment1</name><name>fragment2</name></absolute-ordering></web-app>
还可以在web-fragment.xml
里面通过before,after
标签来定义这些配置文件的先后顺序&#xff0c;这里不再举例这步主要是根据顺序&#xff0c;将这些配置文件加到集合orderedFragments
中。
2.2 ServletContainerInitializers的实现类
这也是servlet 3.0新增的特性&#xff0c;容器在启动时使用 JAR 服务 API(JAR Service API) 来发现 ServletContainerInitializer
的实现类&#xff0c;并且容器将 WEB-INF/lib
目录下 JAR 包中的类都交给该类的 onStartup()
方法处理&#xff0c;我们通常需要在该实现类上使用 &#64;HandlesTypes
注解来指定希望被处理的类&#xff0c;过滤掉不希望给 onStartup()
处理的类。
在onStartup方法中可以优先加载这些类&#xff0c;或者修改其中的方法等。这步主要是把这些类找到放到Set scis
中&#xff0c;进而放入typeInitializerMap&#xff1b;
protected void processServletContainerInitializers() {Set<ServletContainerInitializer> scis &#61;typeInitializerMap.get(type);if (scis &#61;&#61; null) {scis &#61; new HashSet<>();typeInitializerMap.put(type, scis);}scis.add(sci);
2.3 web.xml文件加载的细节
只要知道了web.xml加载路径信息即可&#xff1a;
参考&#xff1a;《Tomcat学习之ContextConfig》