Spring 攔截器和過濾器中自動注入為 null 的原因及解決方案

Darren i發表於2020-10-27

起因

開發過程中在過濾器(filter)中注入Bean出現空指標異常,通過查詢資料瞭解空指標的原因,特此記錄。

問題分析

由於其他bean在service,controller層注入一點問題也沒有,開始根本沒意識到Bean無法注入是在攔截器中無效的問題。

  1. SpringBoot專案的Bean裝配預設規則是根據Application類所在的包位置從上往下掃描!
    “Application類”是指SpringBoot專案入口類。這個類的位置很關鍵:
    如果Application類所在的包為:com.root.app,則只會掃描com.root.app包及其所有子包,如果service或dao所在包不在com.root.app及其子包下,則不會被掃描!
    即, 把Application類放到dao、service所在包的上級,com.root.Application
    我出問題的類確實在Application類子包下面,排除此項。
  2. 意識到只是攔截器(或過濾器)上會有這樣的問題,查詢原因應該是:
    攔截器執行在自動bean初始化之前導致這個問題的。

Spring web中各個元素的初始化順序

在web.xml中各個元素的執行順序:

context-param–>listener–>filter–>servlet

而攔截器是在Spring MVC中配置的,如果從整個專案中看,一個servlet請求的執行過程就變成了這樣:

context-param–>listener–>filter–>servlet–>interceptor(指的是攔截器)

為什麼攔截器是在servlet執行之後,因為攔截器本身就是在servlet內部的。

元素具體概念

  • context-param:就是一些需要初始化的配置,放入context-param中,從而被監聽器(這裡特指org.springframework.web.context.ContextLoaderListener)監聽,然後載入;

  • listener(監聽器):就是對專案起到監聽的作用,它能感知到包括request(請求域),session(會話域)和applicaiton(應用程式)的初始化和屬性的變化;

  • filter(過濾器):就是對請求起到過濾的作用,它在監聽器之後,作用在servlet之前,對請求進行過濾;

  • servlet:就是對request和response進行處理的容器,它在filter之後執行,servlet其中的一部分就是controller層(標記為servlet_2),還包括渲染檢視層(標記為servlet_3)和進入controller之前系統的一些處理部分(servlet_1),另外我們把servlet開始的時刻標記為servlet_0,servlet結束的時刻標記為servlet_4。

  • interceptor(攔截器):就是對請求和返回進行攔截,它作用在servlet的內部,具體來說有三個地方:
    1)servlet_1和servlet_2之間,即請求還沒有到controller層

    2)servlet_2和servlet_3之間,即請求走出controller層次,還沒有到渲染時圖層

    3)servlet_3和servlet_4之間,即結束檢視渲染,但是還沒有到servlet的結束

解決方案

  1. 使用WebApplicationContext 上下文物件來手動注入
  2. 在專案中繼承“WebMvcConfigurerAdapter”類的類中新增攔截器類作為一個Bean(推薦)

問題原因

造成null的原因是因為攔截器載入是在springcontext建立之前完成的,所以在攔截器中注入實體自然就為null。

注入為null的時候,是通過new的方式建立的攔截器,通過new出來的例項是沒有交給spring進行管理的,沒有被spring管理的例項,spring是無法自動注入bean的,所以為null

參考連線:

  • https://blog.csdn.net/ycf921244819/article/details/91388440
  • https://www.cnblogs.com/shamo89/p/8534580.html

相關文章