详解web.xml中元素的加载顺序

一、背景

  最近在项目中遇到了启动时出现加载service注解注入失败的问题,后来经过不懈努力发现了是因为web.xml配置文件中的元素加载顺序导致的,那么就抽空研究了以下tomcat在启动时web.xml文件中元素的加载顺序,现在和大家分享。

二、问题剖析和研究结果

  遇到这种问题的时候,一般看源码是最直接和最权威的获取答案的方式,根据tomcat架构设计Context的实现类是StandardContext,全称org.apache.catalina.core.StandardContext。看到其实现Lifecycle接口,我们在StandardContext中找到startInternal方法,下面给出我把暂时无用的代码去掉后的注释版源码:

 1 /**
 2 * Start this component and implement the requirements
 3 * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
 4 *
 5 * @exception LifecycleException if this component detects a fatal error
 6 *  that prevents this component from being used
 7 */
 8 @Override
 9 protectedsynchronized void startInternal() throwsLifecycleException {
10  //设置webappLoader 代码省略
11  
12  // Standard container startup 代码省略
13  
14   try{
15  
16     // Set up the context init params 
17     //初始化context-param节点数据
18     mergeParameters();
19  
20  
21     // Configure and call application event listeners
22     //配置和调用应用程序事件listeners 
23     if(ok) {
24       if(!listenerStart()) {
25         log.error("Error listenerStart");
26         ok = false;
27       }
28     }
29  
30     // Configure and call application filters
31     //配置和调用应用程序filters
32     if(ok) {
33       if(!filterStart()) {
34         log.error("Error filterStart");
35         ok = false;
36       }
37     }
38  
39     // Load and initialize all "load on startup" servlets
40     //加载和初始化配置在load on startup的servlets
41     if(ok) {
42       loadOnStartup(findChildren());
43     }
44  
45     // Start ContainerBackgroundProcessor thread
46     super.threadStart();
47   }finally{
48     // Unbinding thread
49     unbindThread(oldCCL);
50   }
51  
52 }

那我们接着归纳和整理一下代码:

  1.首先初始化context-param节点

  2.接着配置和调用listeners 并开始监听

  3.然后配置和调用filters filters开始起作用

  4.最后加载和初始化配置在load on startup的servlets

即元素加载顺序为:

context-param --> listeners --> filters --> servlets

注意:

  1.该加载顺序并不会受元素在web.xml文件中的位置的影响。

  2.但对于某类配置节而言,与它们出现的顺序是有关的。以 filter 为例,web.xml 中当然可以定义多个 filter,与 filter 相关的一个配置节是 filter-mapping,这里一定要注意,对于拥有相同 filter-name 的 filter 和 filter-mapping 配置节而言,filter-mapping 必须出现在 filter 之后,否则当解析到 filter-mapping 时,它所对应的 filter-name 还未定义。web 容器启动时初始化每个 filter 时,是按照 filter 配置节出现的顺序来初始化的,当请求资源匹配多个 filter-mapping 时,filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法的。

接着让我们来回忆一下web项目的启动顺序

  1.web容器读取web.xml配置文件,并首先读取<context-param>和<listener>两个结点。

  2.容器创建一个ServletContext(servlet上下文),该web项目的所有部分都将共享这个上下文。

  3.容器将<context-param>转换为键值对,并交给servletContext。

  4.容器按照load on startup中的启动顺序创建<listener>中的类实例,创建监听器。

关于load on startup

  load-on-startup 元素在web应用启动的时候指定了servlet被加载的顺序,它的值必须是一个整数。

  如果它的值是一个负整数或是这个元素不存在,那么容器会在该servlet被调用的时候,加载这个servlet 。

  如果值是正整数或零,容器在配置的时候就加载并初始化这个servlet,容器必须保证值小的先被加载。如果值相等,容器可以自动选择先加载谁。

  正数的值越小,启动该servlet的优先级越高。

三、总结

  通过研究源码我们明白了web.xml中各个元素的加载顺序,再遇到这种问题,我们就可以很快的定位出问题所在了。由此也发现和体会到了研究源码是一种很好的习惯也是解决问题不可缺少的方式。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏haifeiWu与他朋友们的专栏

Redis协议规范(译文)

Redis客户端使用名为RESP(Redis序列化协议)的协议与Redis服务器进行通信。 虽然该协议是专为Redis设计的,但它可以用于其他CS软件项目的通讯...

1623
来自专栏静晴轩

Android项目中文字乱码问题

Eclipse之所以会出现乱码问题是因为eclipse编辑器选择的编码规则是可变的。一般默认都是UTF-8或者GBK(对于字符编码可参见字符编码的故事),当从外...

39211
来自专栏大闲人柴毛毛

Java并发编程的艺术(十二)——线程安全

1. 什么是『线程安全』? 如果一个对象构造完成后,调用者无需额外的操作,就可以在多线程环境下随意地使用,并且不发生错误,那么这个对象就是线程安全的。 2. ...

3735
来自专栏Android 研究

Android系统启动——3init.rc解析

init.rc文件是以“块”(section)为单位服务的,,一个“块”(section)可以包含多行。“块”(section)分成两大类:一类称为"动作(ac...

4062
来自专栏python3

python3--基础综合测试

解释:char类型在python中不存在,它是其他编程语言的一种数据类型,比如C/C++,JAVA

1381
来自专栏york技术分享

sed 使用教程 - 通读篇(30分钟入门系列)

和上篇 awk 分享一样,作为通读性的分享,不想引入太过复杂的东西,依然从日常工作中碰到的 80% 的需求出发,重点阐述最重点的部门,工作原理等,普及一些对se...

48622
来自专栏Pythonista

vim与程序员

所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在。

1772
来自专栏开发 & 算法杂谈

Linux常用shell语法和命令

判断/home/oicq/script/get_random_shm_key.sh是否存在

3462
来自专栏程序员互动联盟

【专业技术】在C/C++程序中打印当前函数调用栈

前几天帮同事跟踪的一个程序莫名退出,没有core dump(当然ulimit是打开的)的问题。我们知道,正常情况下,如果程序因为某种异常条件退出的话,应该会产生...

3064
来自专栏安恒网络空间安全讲武堂

专题 | Python编写渗透工具学习笔记一

目录&基础知识 0x00 Python编程中一些模块的简单介绍(基础知识) 0x01web目录扫描程序 --脚本代码的实现和分析 --优化脚本 0x02实现一个...

3367

扫码关注云+社区

领取腾讯云代金券