• 欢迎访问 winrains 的个人网站!
  • 本网站主要从互联网整理和收集了与Java、网络安全、Linux等技术相关的文章,供学习和研究使用。如有侵权,请留言告知,谢谢!

Tomcat 7 中 web 应用加载原理(2):web.xml 解析

Tomcat winrains 来源:预流 11个月前 (10-29) 33次浏览
前一篇文章讲了org.apache.catalina.startup.HostConfig的 lifecycleEvent 方法中所做的事情。最后看到在 Tomcat 启动时或启动后(后台线程定时扫描)会调用 HostConfig 类的 deployApps 方法:

可以看到这里部署应用有三种方式:XML 文件描述符、WAR 包、文件目录。三种方式部署的总体流程很相似,都是一个 web 应用分配一个线程来处理,这里统一放到与 Host 内部的线程池对象中( startStopExecutor ),所以有时会看到在默认配置下 Tomcat 启动后可能有一个叫-startStop-的线程还会运行一段时间才结束。但浏览这三种部署方式的实现代码,里面都是构建一个 Context 对象,并将构建好的 Context 对象与 Host 组件关联起来(即调用host.addChild(context)这句,具体代码在 HostConfig 类的deployDescriptor(ContextName cn, File contextXml)deployDirectory(ContextName cn, File dir)deployWAR(ContextName cn, File war)三个方法中,这里不再贴出代码来详细分析)。前一篇文章只分析到这步,可以看出与一个 web 应用相对应的一个 Context 对象已经构建出来了,但如果容器只执行到这里根本无法响应一个浏览器的一次请求。就 web 服务器的实现来看一次请求过来除了需要根据内部 Context 构建找到这次请求访问的web应用具体所对应的 Context 对象,还需要包含 web 应用中具体的哪个 Servlet 来处理这次请求,中间是否还需要执行相应的过滤器( filter )、监听器( listener )等,做过 java 的 web 开发的同学都知道,这些信息是配置在一个 web 应用的WEB-INF\web.xml文件的(servlet3 中已经支持将这些配置信息放到 Java 文件的注解中,但万变不离其宗,总归要在 web 应用的某个地方说明,并在容器启动时加载,这样才能真正提供 web 服务,响应请求)。
看到这里可以猜到 Tomcat 容器加载 web 应用时必定会有对于每个应用的 web.xml 文件的解析过程,本文就来看看这个解析过程。
在本文开头提到的三种部署应用的实现代码中有一些共通的代码,这里摘出来说明一下:

Class<?> clazz = Class.forName(host.getConfigClass());
LifecycleListener listener =
    (LifecycleListener) clazz.newInstance();
context.addLifecycleListener(listener);
host.addChild(context);

第一段是在所有 Context 对象构建时会添加一个监听器,这里监听器的类名是 StandardHost 类的实例变量 configClass ,其默认值就是org.apache.catalina.startup.ContextConfig。第二段是将当前构建的 Context 对象添加到父容器 Host 对象中。
先看 StandardHost 的 addChild 方法的实现:

可以看到这段代码最后调用了父类的 addChild 方法:

这里看下 addChildInternal 方法的实现:

可以看到会调用子容器的 start 方法,就是指调用 StandardContext 的 start 方法。即给 host 对象添加子容器时将会调用子容器的 start 方法,按照前面文章的分析,调用 StandardContext 的 start 方法最终会调用org.apache.catalina.core.StandardContext类的 startInternal 方法(该方法代码较长,建议自己阅读,不再贴出),这里将会发布一系列事件,按调用前后顺序这些事件包括:BEFORE_INIT_EVENTAFTER_INIT_EVENTBEFORE_START_EVENTCONFIGURE_START_EVENTSTART_EVENTAFTER_START_EVENT
前面提到在构建 Context 对象时都会注册一个监听器org.apache.catalina.startup.ContextConfig,看下这个类的 lifecycleEvent 方法中(为什么会执行这个方法可以看这篇文章的分析)监听了哪些事件:

与 Context 的 start 方法调用相关的事件监听前后顺序为:AFTER_INIT_EVENT(执行 init 方法)、BEFORE_START_EVENT(执行 beforeStart 方法)、CONFIGURE_START_EVENT(执行 configureStart 方法)。在 configureStart 方法将直接调用 webConfig 方法,正是在这个方法中将会解析 web.xml 文件:

这个方法里面做的事情,在英文注释中说的很清楚了,概括起来包括合并 Tomcat 全局 web.xml 、当前应用中的 web.xml 、web-fragment.xml 和 web 应用的注解中的配置信息,并将解析出的各种配置信息(如 servlet 配置、filter 配置等)关联到 Context 对象中(在上面的代码第 140 行:webXml.configureContext(context))。看下 configureContext 方法:

可以看到里面对 context 调用了各种 set、add 方法,从而将 web.xml 中的各种配置信息与表示一个 web 应用的 context 对象关联起来。

作者:预流

来源:https://juejin.im/post/5a7aa6f4f265da4e7e10a0aa


版权声明:文末如注明作者和来源,则表示本文系转载,版权为原作者所有 | 本文如有侵权,请及时联系,承诺在收到消息后第一时间删除 | 如转载本文,请注明原文链接。
喜欢 (1)