Servlet過濾器提供了一種強大的機制來攔截和操作傳入請求。然而,在這些過濾器中訪問 Spring 管理的 bean 可能會帶來挑戰。
在本教程中,我們將探索在Servlet過濾器中無縫獲取 Spring bean 的各種方法,這是基於 Spring 的 Web 應用程式中的常見要求。
@Autowired
雖然 Spring 的依賴注入機制@Autowired是將依賴項注入到 Spring 管理的元件中的一種便捷方法,但它不能與Servlet過濾器無縫配合。這是因為Servlet過濾器是由Servlet容器初始化的,通常是在 Spring 的ApplicationContext完全載入和初始化之前。
因此,當容器例項化Servlet過濾器時,Spring 上下文可能尚不可用,從而在嘗試使用@Autowired註釋時導致 null 或未初始化的依賴項。讓我們探索在Servlet過濾器中訪問 Spring bean 的替代方法。
設定
讓我們建立一個通用的LoggingService,它將自動連線到我們的過濾器中:
@Service |
然後,我們將建立過濾器,它將攔截傳入的 HTTP 請求,以使用LoggingService依賴項記錄 HTTP 方法和 URI 詳細資訊:
@Component |
讓我們公開一個返回使用者列表的RestController :
@RestController |
我們將設定測試來檢查LoggingService是否已成功自動連線到我們的過濾器中:
@RunWith(SpringRunner.class) |
然而,在這個階段,LoggingService 可能不會被注入到LoggingFilter中,因為 Spring 上下文尚不可用。我們將在以下部分中探討解決此問題的各種選項。
1、在Servlet Filter中使用SpringBeanAutowiringSupport
Spring 的SpringBeanAutowiringSupport類提供對非 Spring 管理的類(例如Filter和Servlet)的依賴注入的支援。透過使用此類,Spring 可以將依賴項(例如LoggingService(Spring 管理的 bean))注入到LoggingFilter中。
init方法用於初始化Filter例項,我們將在 LoggingFilter 中重寫此方法以使用SpringBeanAutowiringSupport:
@Override |
processInjectionBasedOnServletContext方法使用與ServletContext關聯的ApplicationContext來執行自動裝配。它首先從ServletContext檢索 ApplicationContext ,然後使用它將依賴項自動裝配到目標物件中。此過程涉及檢查目標物件的欄位中是否有@Autowired註釋,然後從ApplicationContext解析並注入相應的 beans 。
該機制允許非 Spring 管理的物件(如過濾器和 servlet)從 Spring 的依賴注入功能中受益。
2、在Servlet Filter中使用WebApplicationContextUtils
WebApplicationContextUtils提供了一個實用方法,用於檢索與 ServletContext 關聯的ApplicationContext 。ApplicationContext包含 Spring 容器管理 的 所有 bean。
讓我們重寫LoggingFilter類的init方法:
@Override |
我們從ApplicationContext中檢索LoggingService的例項,並將其分配給過濾器的loggingService欄位。當我們需要在非 Spring 管理的元件(例如Servlet或Filter)中訪問 Spring 管理的 bean ,並且無法使用基於註釋或建構函式注入時,此方法非常有用。
需要注意的是,這種方法將過濾器與 Spring 緊密耦合,在某些情況下可能並不理想。
3、在配置中使用FilterRegistrationBean
FilterRegistrationBean用於以程式設計方式在 servlet 容器中註冊Servlet過濾器。它提供了一種在應用程式的配置類中動態配置過濾器註冊的方法。
透過使用@Bean和@Autowired註解該方法,LoggingService會自動注入到該方法中,從而允許將其傳遞給LoggingFilter建構函式。讓我們在配置類中設定FilterRegistrationBean的方法:
@Bean |
然後,我們將在LoggingFilter中包含一個建構函式來支援上述配置:
public LoggingFilter(LoggingService loggingService) { |
這種方法集中了過濾器及其依賴項的配置,使程式碼更有組織性並且更易於維護。
4、在Servlet Filter中使用DelegatingFilterProxy
DelegatingFilterProxy 是一個Servlet過濾器,它允許將控制傳遞給有權 訪問 Spring ApplicationContext的Filter類。
讓我們配置DelegatingFilterProxy以委託給名為“loggingFilter”的 Spring 管理的 bean 。Spring 使用FilterRegistrationBean在應用程式啟動時向Servlet容器註冊過濾器:
@Bean |
讓我們為之前定義的過濾器使用相同的 bean 名稱:
@Component(<font>"loggingFilter") |
這種方法允許我們使用Spring的依賴注入來管理loggingFilter bean。
比較Servlet Filter中的依賴注入方法
DelegatingFilterProxy方法與SpringBeanAutowiringSupport和直接使用WebApplicationContextUtils的不同之處在於它如何將過濾器的執行委託給 Spring 管理的 bean,從而允許我們使用 Spring 的依賴注入。
DelegatingFilterProxy與典型的 Spring 應用程式架構更好地保持一致,並允許更清晰地分離關注點。FilterRegistrationBean方法允許對過濾器的依賴項注入進行更多控制,並集中依賴項的配置。
相比之下,SpringBeanAutowiringSupport和WebApplicationContextUtils是更底層的方法,在我們需要對過濾器的初始化過程進行更多控制或想要直接訪問ApplicationContext 的某些場景中非常有用。然而,它們需要更多的手動設定,並且不提供與 Spring 依賴注入機制相同級別的整合。