容器先初始化所有再初始化所有,且均按 web.xml中声明顺序执行 init;请求处理时按顺序执行Filter,再调用匹配的servlet。

web.xml 中的 <filter></filter> 和 <servlet></servlet> 本身没有直接的“加载顺序”依赖,但它们的 初始化顺序 是有明确规则的:容器先初始化所有 <filter></filter>,再初始化所有 <servlet></servlet>。
filter 初始化早于 servlet
根据 Servlet 规范,Web 容器(如 tomcat)在应用启动时按以下顺序处理:
- 解析 web.xml,收集所有
<filter></filter>和<servlet></servlet>声明 - 按 web.xml 中声明的 ** 先后顺序 **,依次调用每个
Filter.init() - 再按 web.xml 中声明的 ** 先后顺序 **,依次调用每个
Servlet.init()
也就是说,哪怕某个 servlet 在 web.xml 中写在 filter 前面,只要它被声明为 <servlet></servlet>,就不会比任何 <filter></filter> 先 init —— 规范强制要求 filter 优先就绪。
filter-mapping 和 servlet-mapping 决定执行顺序
真正影响请求处理流程的是映射(mapping)配置,而非声明顺序:
-
<filter-mapping></filter-mapping>中的<url-pattern></url-pattern>或<servlet-name></servlet-name>决定了哪些请求会经过该 filter -
<servlet-mapping></servlet-mapping>决定了哪个 servlet 负责处理匹配的请求 - 当一个请求同时匹配多个 filter 和一个 servlet 时,执行顺序是:
→ 所有匹配的 filter(按<filter-mapping></filter-mapping>在 web.xml 中的顺序)→ 目标 servlet → filter 链逆序执行 doFilter 后续逻辑(即“出 栈”)
可通过 load-on-startup 控制 servlet 初始化时机
虽然 servlet 总是在 filter 之后初始化,但你可以用 <load-on-startup></load-on-startup> 指定 servlet 的相对优先级(仅限 servlet 之间):
- 值越小越早 init(如 0 比 1 早)
- 未设置或负数,则在首次请求时才初始化
- 这个值对 filter 无效 —— filter 默认都是启动时加载,且不支持 load-on-startup
实际开发建议
不必纠结“谁先加载”,重点应放在:
- 确保 filter 不依赖尚未 init 的 servlet(因为 servlet 此时确实还没 ready)
- 把公共逻辑(如 编码、登录检查、日志)放在 filter,业务逻辑放 servlet
- 多个 filter 之间注意顺序:比如 CharacterEncodingFilter 应放在其他 filter 前面,才能保证后续 filter 读取参数时 编码 正确
基本上就这些。规范很明确,行为可预期,关键还是 mapping 配得对不对。