Filter无法直接@Autowired是因为其由Servlet容器管理而非Spring容器创建,需在init()中通过WebApplicationContextUtils获取Bean;@Component方式存在实例化和时机隐患,不推荐;ApplicationContextAware无效。

Filter中无法直接@Autowired的原因
Java Web的Filter由Servlet容器(如Tomcat)管理,不是Spring容器创建的Bean,因此不经过Spring的生命周期管理,@Autowired字段会为null。这不是配置遗漏,而是加载时机和上下文隔离导致的根本限制。
通过WebApplicationContext手动获取Bean
在Filter的init()方法中,利用ServletContext拿到Spring根上下文,再从中获取所需Bean。这是最常用、最稳妥的方式,适用于所有Spring版本(包括Spring Boot)。
- 必须在
init()中获取,不能在构造函数或类变量初始化时调用 - 推荐使用
WebApplicationContextUtils.getRequiredWebApplicationContext(sc),避免返回null - 若项目有多个上下文(如父子容器),确保获取的是根上下文(即
ContextLoaderListener加载的那个)
public class MyFilter implements Filter {
private MyService myService;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
ServletContext sc = filterConfig.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
myService = ctx.getBean(MyService.class);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 此时myService已可用
myService.doSomething();
chain.doFilter(request, response);
}
}
@Component + @Order + Spring Boot自动注册的陷阱
Spring Boot允许将Filter声明为@Component,并用@Order控制顺序,此时它会被Spring托管,@Autowired看似能用——但存在严重隐患:
- 该方式依赖
FilterRegistrationBean自动注册,但部分场景(如使用web.xml或嵌入式容器自定义配置)可能失效 - 如果
Filter被多个ServletRegistrationBean引用,可能被多次实例化,@Autowired行为不可控 - 某些Spring Boot版本中,
@ComponentFilter的init()早于Spring上下文刷新完成,仍可能报NullPointerException
结论:不推荐仅靠@Component解决依赖注入,应始终以WebApplicationContext手动获取为准。
立即学习“Java免费学习笔记(深入)”;
【极品模板】出品的一款功能强大、安全性高、调用简单、扩展灵活的响应式多语言企业网站管理系统。 产品主要功能如下: 01、支持多语言扩展(独立内容表,可一键复制中文版数据) 02、支持一键修改后台路径; 03、杜绝常见弱口令,内置多种参数过滤、有效防范常见XSS; 04、支持文件分片上传功能,实现大文件轻松上传; 05、支持一键获取微信公众号文章(保存文章的图片到本地服务器); 06、支持一键
使用ApplicationContextAware的替代方案(慎用)
有人尝试让Filter实现ApplicationContextAware,但这行不通——因为Filter本身不是Spring Bean,setApplicationContext()根本不会被调用。强行实现只会让代码看起来“支持注入”,实际运行时依旧null。
真正可行的变通是:写一个静态工具类封装WebApplicationContext访问逻辑,在任意地方(包括Filter)调用SpringUtils.getBean(Xxx.class)。但要注意静态持有ApplicationContext需在ContextRefreshedEvent后赋值,否则可能空指针。
复杂点往往不在“怎么拿”,而在于“什么时候拿才安全”——别信构造器、别信静态块、别信第一次doFilter,只信init()里从ServletContext捞出来的上下文。









