實例化 → 屬性注入 → 【初始化回調】 → Bean 就緒可用 → 容器關閉 → 【銷毀回調】 → 銷毀完成
Spring 容器管理 Bean 從誕生到消亡的全過程,開發者可透過介面、註解或 XML 介入初始化與銷毀兩個關鍵節點。
| 方式 | 實作 | 優缺點 |
|---|---|---|
1. 實作 InitializingBean | void afterPropertiesSet() throws Exception | 強耦合 Spring API,不推薦新專案 |
2. XML init-method | <bean id="x" class="X" init-method="init"/> | 零侵入,方法名自訂,推薦 |
3. 註解 @PostConstruct (JSR-250) | 方法上標註 @PostConstruct | 標準化、可讀性佳,需 javax.annotation 相依 (Java 9+ 需額外引入) |
<bean id="helloWorld" class="com.example.HelloWorld" init-method="init" destroy-method="destroy">
<property name="message" value="Hello World!"/>
</bean>
public class HelloWorld {
private String message;
public void setMessage(String m) { this.message = m; }
public void getMessage() { System.out.println("Msg: " + message); }
public void init() { System.out.println("Bean 初始化中..."); }
public void destroy() { System.out.println("Bean 即將銷毀..."); }
}
| 方式 | 實作 | 適用範圍 |
|---|---|---|
1. 實作 DisposableBean | void destroy() throws Exception | 同 InitializingBean,不推薦 |
2. XML destroy-method | <bean ... destroy-method="cleanup"/> | Singleton Bean,容器關閉時呼叫 |
3. 註解 @PreDestroy (JSR-250) | 方法上標註 @PreDestroy | 標準化,Singleton/Prototype (請求結束) 均適用 |
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// ... 使用 Bean
ctx.registerShutdownHook(); // JVM 關閉時優雅釋放資源
Web 環境下 ContextLoaderListener / DispatcherServlet 已自動註冊。
當大量 Bean 共用相同方法名 (如 init()/destroy()) 時,可在 <beans> 根元素統一宣告:
<beans xmlns="https://www.springframework.org/schema/beans"
default-init-method="init"
default-destroy-method="destroy">
<bean id="beanA" class="com.example.BeanA"/> <!-- 自動綁定 init/destroy -->
<bean id="beanB" class="com.example.BeanB"/>
</beans>
init-method/destroy-method 覆蓋。BeanCreationException,需確保類別確實定義。public class MainApp {
public static void main(String[] args) {
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
HelloWorld bean = ctx.getBean("helloWorld", HelloWorld.class);
bean.getMessage();
ctx.registerShutdownHook(); // 關鍵:確保 destroy 被呼叫
}
}
輸出:
Bean 初始化中...
Msg: Hello World!
Bean 即將銷毀...
若需在初始化前/後對所有 Bean 進行通用處理 (如 AOP 代理建立、欄位解密、驗證),實作 BeanPostProcessor:
public class MyProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("初始化前: " + beanName);
return bean; // 可返回代理物件
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("初始化後: " + beanName);
return bean;
}
}
在 XML 註冊為 Bean 即自動生效 (無需指定目標 Bean)。
@PostConstruct / @PreDestroy:標準、無侵入、IDE 支援佳。InitializingBean/DisposableBean 造成程式碼耦合框架。registerShutdownHook():否則銷毀回調不會執行,資源洩漏 (連線池、執行緒池、檔案鎖)。default-init-method:減少 XML 重複,統一維護。ApplicationRunner/CommandLineRunner 或 @Async 延後執行。ApplicationEvent/@EventListener)