1. 程式人生 > 其它 >Filter使用@Autowired註解失敗及解決辦法

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

以上內容純屬個人總結,如有問題請在評論區留言!