listener → filter → servlet,且同类型按web.xml声明顺序初始化;listener最早用于全局资源初始化,filter在首请求前预处理,servlet默认懒加载或按load-on-startup值在filter后初始化。

web.xml 里 Listener、Filter、Servlet 的加载顺序是固定的
Java Web 容器(如 Tomcat)启动时,web.xml 中三类组件的初始化顺序严格按 Listener → Filter → Servlet 执行,且同类型组件按它们在 web.xml 中的**声明顺序**依次触发。这个顺序不是可配置的,也不受类加载路径或包名影响。
常见错误现象:ServletContextListener.contextInitialized() 里尝试获取某个 Filter 初始化后才设置的上下文属性,结果为 null;或者在 Servlet.init() 中依赖某个 Filter 预加载的缓存,但缓存还没建好。
- Listener 在容器启动最早阶段运行,适合做全局资源初始化(数据库连接池、Spring Context 加载)
- Filter 在第一个请求到达前完成初始化,但晚于 Listener,适合做请求预处理(编码设置、权限校验)
- Servlet 默认是懒加载(首次请求才 init),除非显式配置
<load-on-startup>1</load-on-startup>,此时它会在所有 Filter 初始化完成后立即执行init()
load-on-startup 值只影响 Servlet 加载时机,不改变类型间顺序
load-on-startup 是 Servlet 的专属配置项,值越小越早加载,但再小也**不可能早于 Filter 初始化完成**。设成 -1 或不写,就彻底懒加载;设成 0 或正整数,只是让它在 Filter 全部 init 后、首个请求前被调用。
容易踩的坑:有人以为把 load-on-startup 设成负数能让 Servlet 比 Filter 还早,实际会被容器忽略,等同于未配置;还有人给多个 Servlet 设相同数值,期望它们并行 init,但容器仍按 web.xml 声明顺序串行调用。
立即学习“Java免费学习笔记(深入)”;
- 值为
0:比正数更早,但仍在所有 Filter 之后 - 值为
1和2:都早于懒加载 Servlet,但1一定先于2初始化 - 没写或
-1:首次 HTTP 请求触发init(),此时 Filter 已全部 ready
Listener 和 Filter 的 init 方法里不能依赖 Servlet 的实例
因为 Servlet 实例根本还不存在。哪怕你写了 <load-on-startup>0</load-on-startup>,它的 init() 也发生在所有 Filter.init() 返回之后。所以任何在 ServletContextListener 或 Filter.init() 中试图通过 getServletRegistration() 或反射拿 Servlet 实例的操作,都会失败或返回 null。
典型误用场景:想在 Filter 初始化时“预热”某个 Servlet 的内部状态,或者在 Listener 里注册一个监听器,回调目标是某个 Servlet 的静态方法——这没问题;但如果回调里要访问该 Servlet 的 getServletConfig() 或成员变量,就一定会空指针。
- Listener 只能安全操作
ServletContext、系统属性、外部配置文件 - Filter.init() 可以读取
FilterConfig.getServletContext(),但不能假设某 Servlet 已 init - 真需要跨组件通信,用
ServletContext.setAttribute()+ 监听器模式,别硬耦合实例引用
Spring Boot 项目里 web.xml 不生效,得看 ServletWebServerFactory
如果你用的是 Spring Boot 2.x+,默认没有 web.xml,整个生命周期由 ServletWebServerFactory 控制。这时候 Listener/Filter/Servlet 的注册顺序取决于 Java Config 或注解方式:
- @WebListener 注解类等价于
web.xml中的Listener,优先级最高 - @WebFilter 注册的 Filter,在 Spring 容器刷新后、DispatcherServlet 初始化前生效
- DispatcherServlet 本身是 Servlet,但它是 Spring MVC 的核心,其 init 时机由 Spring Boot 自动管理,不响应
load-on-startup
所以老项目迁移到 Spring Boot 时,别指望复制一份 web.xml 就能复现原顺序——必须改用 ServletRegistrationBean、FilterRegistrationBean 显式控制 order,否则默认顺序可能和预期不符。
最常被忽略的一点:web.xml 的顺序规则只对传统 WAR 包部署有效;只要用了嵌入式容器(Tomcat/Jetty 内置),一切以 Java 配置为准,XML 文件即使存在也可能被完全跳过。










