在 Spring Boot 中註冊 ServletContextListener
1. 簡介
許多應用程式需要在啟動和關閉期間執行特定操作。 Java Servlet API 透過ServletContextListener
介面提供了一種便捷的方式來關聯這些生命週期事件。它會在 Servlet 上下文建立和銷毀時接收通知,使其成為載入配置資料、啟動後台任務或初始化外部資源的理想場所。
雖然在 Java EE 應用程式中,此監聽器通常透過web.xml
註冊,或最好用@WebListener
註釋,但 Spring Boot 提供了避免 XML 配置並與其嵌入式 servlet 容器協同工作的替代方案。
在本教程中,我們將探討如何在 Spring Boot 應用程式中註冊ServletContextListener
。我們將使用 Spring Boot 3.x 和 Jakarta Servlet API 實作一個簡單的監聽器,並研究基於註解和編程式註冊方法。
2.實作ServletContextListener
讓ServletContextListener
先來了解一下ServletContextListener
。它是一個用來接收有關ServletContext
生命週期變化事件的介面。 ServletContextListener允許我們在應用程式啟動和停止時運行程式碼。
因此,它定義了兩個回呼方法— contextInitialized()
和contextDestroyed()
。當 Web 應用程式啟動並初始化ServletContext
時,Servlet 容器會呼叫contextInitialized()
。相反,當 Web 應用程式關閉並即將關閉ServletContext
時,它會呼叫contextDestroyed()
。
為了演示,讓我們建立一個簡單的監聽器來記錄這兩個事件的訊息:
public class CustomLifecycleLoggingListener implements ServletContextListener {
private final Logger log = LoggerFactory.getLogger(CustomLifecycleLoggingListener.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("Application started");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info(" Application stopped");
}
}
容器在每個應用程式生命週期中(在 Web 應用程式活動之前和之後)呼叫這些方法一次。
現在我們已經有了自訂邏輯,讓我們看看如何在 Spring Boot 應用程式中註冊這個監聽器。
3. 在 Spring Boot 註冊
在傳統的 Java EE 應用程式中,Servlet 容器透過@WebListener
註解檢測 Servlet 監聽器。而當我們將 Spring Boot 應用程式作為可執行 JAR 檔案運行時, @WebListener
類別不會被自動偵測到。因此,我們需要明確註冊它們,以便呼叫contextInitialized()
和contextDestroyed()
方法。
Spring Boot 提供了兩種常見的方法來做到這一點。
3.1. 使用WebListener
和ServletComponentScan
註解
讓我們先將@WebListener
註解與@ServletComponentScan
結合使用。
這要求 Servlet API 存在於類別路徑中,Spring Boot 在使用spring-boot-starter-web.
我們只需在監聽器類別上新增@WebListener
註解,並在 Spring Boot 應用程式中啟用 Servlet 元件掃描:
@SpringBootApplication
@ServletComponentScan
public class ServletContextListenerApplication {
public static void main(String[] args) {
SpringApplication.run(ServletContextListenerApplication.class, args);
}
}
如果我們運行該應用程序,我們可以看到配置的日誌:
...
[main] INFO osbwscServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 636 ms
[main] INFO cbsCustomLifecycleLoggingListener - Application started
[main] DEBUG oswfServerHttpObservationFilter - Filter 'webMvcObservationFilter' configured for use
...
總而言之,這種方法更接近傳統的 Java EE 風格,如果我們想保留熟悉的模式,這是一個不錯的選擇。
3.2. 使用ServletListenerRegistrationBean
或者,我們可以使用ServletListenerRegistrationBean
註冊我們的監聽器。
這種方法避免了使用 Servlet 註解,並將組態保留在 Java 程式碼中。由於它不依賴 Servlet API 掃描機制,因此即使在沒有spring-boot-starter-web
專案中也能正常運作。它還支援可執行 JAR 和 WAR 部署,而無需使用@ServletComponentScan
:
@Configuration
public class CustomListenerConfiguration {
@Bean
public ServletListenerRegistrationBean<CustomLifecycleLoggingListener> lifecycleListener() {
return new ServletListenerRegistrationBean<>(new CustomLifecycleLoggingListener());
}
}
Spring 的元件掃描會偵測到ListenerConfiguration
類,並將其定義的ServletListenerRegistrationBean
註冊為 Spring Bean。在應用程式啟動期間, Spring Boot 會註冊底層的CustomLifecycleLoggingListener
類,並在應用程式生命週期的適當時間點呼叫其contextInitialized()
和contextDestroyed()
方法。
4. 結論
在本文中,我們探討如何在 Spring Boot 應用程式中註冊ServletContextListener
。我們實作了一個簡單的監聽器,並示範了兩種註冊方法-使用具有@ServletComponentScan
的@WebListener
註解,以及使用ServletListenerRegistrationBean
。
對於 Java EE 開發者來說,第一種方法可能比較熟悉,但它需要 Servlet 元件掃描,而 Servlet API 必須存在於類別路徑中。而ServletListenerRegistrationBean
是 Spring Boot 原生的監聽器註冊方法。它避免了註解,也不依賴 Servlet API 掃描。
還有其他註冊監聽器的方法,例如透過 servlet 初始化程式碼或 XML 配置手動新增。不過,在現代 Spring Boot 應用程式中,通常不建議使用這些方法。總而言之,如果我們正在建立新的 Spring Boot 應用程式或遷移程式碼, ServletListenerRegistrationBean
是更靈活、更可移植的選擇。
與往常一樣,完整的原始程式碼可在 GitHub 上取得。