Filter使用@Autowired注解失败及解决办法

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);

以上内容纯属个人总结,如有问题请在评论区留言!

原文地址:https://www.cnblogs.com/panchanggui/p/14979829.html