debug启动,观察调用栈:
可见对 @WebFilter 的处理是在SB启动时,在ServletComponentRegisteringPostProcessor被触发,实现对如下注解的的扫描和处理:
- @WebFilter
- @WebListener
- @WebServlet
WebFilterHandler则负责处理 @WebFilter 的使用:
最后,WebServletHandler 通过父类 ServletComponentHandler 的模版方法模式,处理了所有被 @WebFilter 注解的类:
可见最终注册的 FilterRegistrationBean就是自定义的WebFilter。
看第二个问题:
何时实例化TimeCostFilter
TimeCostFilter 是何时实例化的呢?为什么它没有成为一个普通 Bean?
可在 TimeCostFilter 构造器中加断点,便于快速定位初始化时机:
结合源码,可发现:
- Tomcat 启动时(onstartUp),才会创建 FilterRegistrationBean
- FilterRegistrationBean 在被创建时(createBean)会创建 TimeCostFilter 装配自身,而 TimeCostFilter 是通过 ResolveInnerBean 创建的
- TimeCostFilter 实例最终是一种 InnerBean
所以最终 TimeCostFilter 实例是一种 InnerBean,也就无法自动注入了。
修正
找到根因,就知道如何解决了。
前文解析可知,使用 @WebFilter 修饰过滤器时,TimeCostFilter 类型的 Bean 并没有注册至 Spring 容器,真正注册的是 FilterRegistrationBean。
考虑到还可能存在多个 Filter,可这样修改:
- 注入 FilterRegistrationBean 类型,而非 TimeCostFilter 类型
- 注入的名称是包含包名的全限定名,不能直接用
TimeCostFilter,以便存在多个过滤器时,能精确匹配。
总结
@WebFilter 这种方式构建的 Filter 无法直接根据过滤器定义类型自动注入,因为这种Filter本身是以内部Bean呈现,最终是通过FilterRegistrationBean呈现给Spring。
所以可通过自动注入FilterRegistrationBean类型完成自动装配。




