最近在项目中遇到了启动时出现加载service注解注入失败的问题,后来通过不懈努力发现了是由于web.xml配置文件中的元素加载顺序致使的,那么就抽空研究了如下tomcat在启动时web.xml文件中元素的加载顺序,如今和你们分享。web
遇到这种问题的时候,通常看源码是最直接和最权威的获取答案的方式,根据tomcat架构设计Context的实现类是StandardContext,全称org.apache.catalina.core.StandardContext。看到其实现Lifecycle接口,咱们在StandardContext中找到startInternal方法,下面给出我把暂时无用的代码去掉后的注释版源码:apache
那咱们接着概括和整理一下代码:tomcat
1.首先初始化context-param节点架构
2.接着配置和调用listeners 并开始监听app
3.而后配置和调用filters filters开始起做用ide
4.最后加载和初始化配置在load on startup的servletsspa
即元素加载顺序为:架构设计
context-param --> listeners --> filters --> servlets
注意:设计
1.该加载顺序并不会受元素在web.xml文件中的位置的影响。orm
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中各个元素的加载顺序,再遇到这种问题,咱们就能够很快的定位出问题所在了。由此也发现和体会到了研究源码是一种很好的习惯也是解决问题不可缺乏的方式。