Spring干預(yù)Bean的生命周期的方法詳解
Spring 提供了多種機(jī)制讓我們能夠在 Bean 生命周期的不同節(jié)點“插入”自己的邏輯,這些機(jī)制可以分為兩大類:針對單個 Bean 的干預(yù)和針對所有/多個 Bean 的全局干預(yù)。
一、 針對單個 Bean 的干預(yù)(最常用)
這些方法讓你為一個特定的 Bean 類定義其初始化和銷毀邏輯。
1. 使用 JSR-250 注解(推薦方式)
這是現(xiàn)在最優(yōu)雅、也是 Spring 官方推薦的方式。它使用 Java 的標(biāo)準(zhǔn)注解,與 Spring 框架解耦。
@PostConstruct:在依賴注入完成之后,執(zhí)行任何自定義的初始化邏輯。可以把它看作是 Bean 的“構(gòu)造函數(shù)完成后的補(bǔ)充構(gòu)造函數(shù)”。@PreDestroy:在容器銷毀 Bean 之前,執(zhí)行清理工作。
示例:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Service
public class DataProcessor {
@Autowired
private DataSource dataSource; // 依賴會被先注入
private Connection connection;
public DataProcessor() {
System.out.println("1. 調(diào)用構(gòu)造函數(shù): dataSource is null? " + (dataSource == null));
}
@PostConstruct
public void openConnection() {
System.out.println("3. 執(zhí)行 @PostConstruct: dataSource is null? " + (dataSource == null));
System.out.println("正在打開數(shù)據(jù)庫連接...");
// 此時 dataSource 已經(jīng)被注入,可以安全使用
// this.connection = dataSource.getConnection();
}
public void process() {
System.out.println("正在處理數(shù)據(jù)...");
}
@PreDestroy
public void closeConnection() {
System.out.println("執(zhí)行 @PreDestroy: 正在關(guān)閉數(shù)據(jù)庫連接...");
// if (this.connection != null) this.connection.close();
}
}
優(yōu)點:代碼簡潔,與 Spring 解耦,符合 Java EE 規(guī)范。
2. 實現(xiàn) Spring 的特定接口
這是 Spring 早期提供的方式,需要你的 Bean 類實現(xiàn) Spring 框架的接口。
InitializingBean:實現(xiàn)它的afterPropertiesSet()方法,效果同@PostConstruct。DisposableBean:實現(xiàn)它的destroy()方法,效果同@PreDestroy。
示例:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean;
@Component
public class LegacyService implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("執(zhí)行 InitializingBean.afterPropertiesSet()");
}
@Override
public void destroy() throws Exception {
System.out.println("執(zhí)行 DisposableBean.destroy()");
}
}
缺點:代碼與 Spring 框架產(chǎn)生了強(qiáng)耦合,不推薦在新代碼中使用。
3. 在配置中指定 init-method 和 destroy-method
這種方式完全將生命周期邏輯的調(diào)用與 Bean 類本身解耦。適用于你無法修改其源代碼的第三方庫 Bean。
XML 配置:
<bean id="myService" class="com.example.MyService"
init-method="customInit"
destroy-method="customCleanup"/>
Java 配置:
@Configuration
public class AppConfig {
@Bean(initMethod = "customInit", destroyMethod = "customCleanup")
public MyService myService() {
return new MyService();
}
}
優(yōu)點:對類代碼無侵入。
三者執(zhí)行順序:@PostConstruct -> InitializingBean.afterPropertiesSet() -> init-method。
二、 針對所有/多個 Bean 的全局干預(yù)(高級/框架級)
這些機(jī)制是 Spring 框架的強(qiáng)大武器,允許你對容器中所有(或部分)Bean 的生命周期進(jìn)行統(tǒng)一的、批量的處理。
1. BeanPostProcessor(Bean 后置處理器)
這是最重要、最強(qiáng)大的全局干預(yù)接口。它像一個“質(zhì)檢員”,容器中每一個 Bean 在初始化前后都會經(jīng)過它進(jìn)行“檢查”和“加工”。
它有兩個核心方法:
postProcessBeforeInitialization(Object bean, String beanName):在任何 Bean 的初始化方法(如@PostConstruct)調(diào)用前執(zhí)行。postProcessAfterInitialization(Object bean, String beanName):在任何 Bean 的初始化方法調(diào)用后執(zhí)行。
Spring 的 AOP(如 @Transactional)就是通過 BeanPostProcessor 實現(xiàn)的。它在 postProcessAfterInitialization 階段檢查 Bean,如果發(fā)現(xiàn)需要代理,就返回一個代理對象來替換原始的 Bean 實例。
示例: 創(chuàng)建一個打印所有 Bean 初始化信息的后置處理器。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("質(zhì)檢員[Before]: 正在檢查 " + beanName);
return bean; // 必須返回 bean,否則后續(xù)流程拿不到對象
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("質(zhì)檢員[After]: " + beanName + " 已完成初始化。");
// 這里可以返回原始 bean,也可以返回一個包裝后的代理 bean
return bean;
}
}
2. Aware 系列接口
Aware 接口的作用是讓 Bean 能夠“感知”并獲取到它所在的容器環(huán)境資源。這發(fā)生在依賴注入之后,自定義初始化方法之前。
BeanNameAware:讓 Bean 知道它在容器中的 ID。BeanFactoryAware:讓 Bean 獲取到創(chuàng)建它的BeanFactory,從而可以編程方式地獲取其他 Bean。ApplicationContextAware:功能同上,但獲取的是功能更強(qiáng)大的ApplicationContext。
示例:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AwareService implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("AwareService 感知到了 ApplicationContext");
this.context = applicationContext;
}
public void doSomething() {
// 可以通過 context 手動獲取其他 bean
DataProcessor processor = context.getBean(DataProcessor.class);
processor.process();
}
}
注意:過度使用 Aware 接口會增加代碼與 Spring 容器的耦合度,應(yīng)謹(jǐn)慎使用。
總結(jié)
| 干預(yù)方式 | 作用階段 | 影響范圍 | 推薦度/適用場景 |
|---|---|---|---|
| @PostConstruct / @PreDestroy | 初始化后 / 銷毀前 | 單個 Bean | 強(qiáng)烈推薦,代碼清晰,與框架解耦。 |
| InitializingBean / DisposableBean | 初始化后 / 銷毀前 | 單個 Bean | 不推薦,與 Spring 強(qiáng)耦合,用于兼容老代碼。 |
| init-method / destroy-method | 初始化后 / 銷毀前 | 單個 Bean | 推薦,用于無法修改源碼的第三方 Bean。 |
| BeanPostProcessor | 初始化前后 | 所有 Bean | 高級/框架級。用于實現(xiàn) AOP、自定義注解處理等全局邏輯。 |
| Aware 接口 | 初始化前 | 單個 Bean | 謹(jǐn)慎使用。當(dāng) Bean 需要主動與容器交互時使用。 |
簡單來說,作為應(yīng)用開發(fā)者,你的首選和絕大多數(shù)情況下的選擇應(yīng)該是 @PostConstruct 和 @PreDestroy。 如果你需要開發(fā)框架級別的功能,那么 BeanPostProcessor 則是你的核武器。
以上就是Spring干預(yù)Bean的生命周期的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring干預(yù)Bean生命周期的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java畢業(yè)設(shè)計實戰(zhàn)之工作管理系統(tǒng)的實現(xiàn)
這是一個使用了java+SSM+Jsp+Mysql開發(fā)的工作干活管理系統(tǒng),是一個畢業(yè)設(shè)計的實戰(zhàn)練習(xí),具有管理系統(tǒng)該有的所有功能,感興趣的朋友快來看看吧2022-02-02
intellij idea如何配置網(wǎng)絡(luò)代理
intellij idea所在的這臺電腦本身上不了網(wǎng),要通過代理上網(wǎng),那么intellij idea怎么設(shè)置代理上網(wǎng)呢?今天通過本文給大家分享intellij idea如何配置網(wǎng)絡(luò)代理,感興趣的朋友一起看看吧2023-10-10
SpringBoot實現(xiàn)聯(lián)表查詢的代碼詳解
這篇文章主要介紹了SpringBoot中如何實現(xiàn)聯(lián)表查詢,文中通過代碼示例和圖文結(jié)合的方式講解的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-05-05
springboot實現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄(思路詳解)
這篇文章主要介紹了springboot實現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
解決springboot 2.x集成log4j2調(diào)試日志無法關(guān)閉的問題
這篇文章主要介紹了解決springboot 2.x集成log4j2調(diào)試日志無法關(guān)閉的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

