filter中无法使用@Autowired 原因
在Spring中,web应用启动的顺序是:listener->filter->servlet,先初始化listener,然后再来就filter的初始化,再接着才到我们的dispathServlet的初始化,因此,当我们需要在filter里注入一个注解的bean时,就会注入失败,因为filter初始化时,注解的bean还没初始化,没法注入。
由一个简单filter的使用引发的“血案”
前情回顾:项目需要一个filter过滤器来拦截所有请求,过滤器的内容很简单,就是过滤请求url判断用户是否登录。如果用户登录,则更新存在redis里的用户信息过期时间;如果未登录则返回信息给前端,跳转登录。
<filter> <filter-name>ExtensionFilter</filter-name> <filter-class>com.extension.filters.ExtensionFilter</filter-class> </filter> <filter-mapping> <filter-name>ExtensionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
给自己挖的坑:
首先在这个filter过滤器中,需要从请求头中获取token,根据token从redis中拿到用户信息。此时需要在filter中注入封装好的redis实体bean,我使用@Autowired注解,此时代码编译没有报错,看起来程序没问题。
接下来就是在坑里转悠直到把坑填上:
紧接着问题就来了,项目能正常跑起来,但是一请求就报NULLPOINTEREXCEPTION异常,debug调试也找不到原因。折磨了我将近半个小时,终于找到问题。细心阅读并且对Web容器初始化熟悉的朋友应该知道我犯了什么错误了。
问题:在过滤器中采用@Autowired方式注入
1 @Autowired 2 rivate RedisCache redisCache;
然鹅,实际证明注入失败。
分析原因:Web容器初始化顺序是按照Listener-filter-servlet的顺序进行,因为dispatcherServlet是在filter之后才进行初始化,也就是这个时候我们要自动注入的bean才被初始化。所以此时在filter中自动注入的时候还没有bean,所以会注入失败。
解决办法:
1、采用xml配置方式
- Web.xml这样配置
<filter> <filter-name>ExtensionFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>ExtensionFilter</param-value> </init-param> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>DelegatingFilterProxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
- 在spring配置文件中使用bean标签配置serviceImpl和ExtensionFilter
<bean id="ExtensionFilter" class="com.extension.filters.ExtensionFilter"> <property name="redisCache" ref="redisCache"></property> </bean> <!--要注入的bean--> <bean id="redisCache" class="com.htjc.interceptor.redis.RedisCache"> </bean>
这种方式的重点是在web.xml中用到了DelegatingFilterProxy这个filter代理类。具体用法可以去看看DelegatingFilterProxy源码。
2、使用ApplicationContext对象获取
//要注入的对象 private RedisCache redisCache; ServletContext context = request.getServletContext(); ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context); redisCache = ctx.getBean(RedisCache.class);
以上内容纯属个人总结,如有问题请在评论区留言!