当前位置: 首页 > news >正文

详解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中各个元素的加载顺序,再遇到这种问题,我们就可以很快的定位出问题所在了。由此也发现和体会到了研究源码是一种很好的习惯也是解决问题不可缺少的方式。

相关文章:

  • HDU 5773 The All-purpose Zero
  • 整理样本标签
  • OpenSSL命令---s_client
  • Wireshark设置interface 时提示“There are no interfaces on which a capture can be done ”
  • MooseFS维护技巧集锦
  • linux 文件管理
  • Java安全——提供者相关的体系架构
  • 服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
  • vijos 1426
  • 百度地图获取应用SHA1
  • Android Design Support Library使用详解——Snackbar
  • linux安全之iptables防火墙详解1
  • Python学习总结13:os模块
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 虚拟机的封装
  • 【391天】每日项目总结系列128(2018.03.03)
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • CAP 一致性协议及应用解析
  • nodejs:开发并发布一个nodejs包
  • Nodejs和JavaWeb协助开发
  • python 学习笔记 - Queue Pipes,进程间通讯
  • 技术:超级实用的电脑小技巧
  • 京东美团研发面经
  • 漂亮刷新控件-iOS
  • 使用Swoole加速Laravel(正式环境中)
  • 通信类
  • 详解NodeJs流之一
  • 小程序开发中的那些坑
  • 再谈express与koa的对比
  • ​比特币大跌的 2 个原因
  • #QT(智能家居界面-界面切换)
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • #预处理和函数的对比以及条件编译
  • (多级缓存)多级缓存
  • (转载)CentOS查看系统信息|CentOS查看命令
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .net 使用ajax控件后如何调用前端脚本
  • @GetMapping和@RequestMapping的区别
  • @RequestMapping-占位符映射
  • [ C++ ] STL priority_queue(优先级队列)使用及其底层模拟实现,容器适配器,deque(双端队列)原理了解
  • [AIGC] Java 和 Kotlin 的区别
  • [android学习笔记]学习jni编程
  • [AutoSar NVM] 存储架构
  • [bzoj1912]异象石(set)
  • [bzoj4010][HNOI2015]菜肴制作_贪心_拓扑排序
  • [C++]命名空间等——喵喵要吃C嘎嘎
  • [EFI]Atermiter X99 Turbo D4 E5-2630v3电脑 Hackintosh 黑苹果efi引导文件
  • [LeetCode] 148. Sort List 链表排序
  • [LeetCode][LCR178]训练计划 VI——使用位运算寻找数组中不同的数字
  • [Linux] Linux入门必备的基本指令(不全你打我)
  • [Linux] PXE批量装机