bean的生命週期
粗略劃分5步
- 實例化bean
調用的是無參數的構造方法
- bean屬性賦值
執行set注入
- 初始化bean
調用bean的init()方法,需要自己寫,自己配
-
使用bean
-
銷燬bean
調用bean的destroy(),需要自己寫,自己配
注意:自定義的init()和destroy()需要在配置文件配置
<!-- init-method指定初始化方法,destroy-method指定銷燬方法-->
<!-- 這兩個方法需要在bean類中定義-->
<bean id="user" class="com.ali.bean.User" init-method="initBean" destroy-method="destroyBean"></bean>
進一步七步
在以上的5步中,第三步是初始化bean。其實可以在初始化之前和初始化之後添加代碼。此時,需要加入“Bean後處理器”。
編寫一個類實現BeanPostProcessor類,並重寫before和after方法
- 實例化bean
調用的是無參數的構造方法
- bean屬性賦值
執行set注入
- 執行“Bean後處理器”的before方法
- 初始化bean
調用bean的init()方法,需要自己寫,自己配
-
執行“Bean後處理器”的after方法
-
使用bean
-
銷燬bean

// 日誌類bean後處理器
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor befor方法");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor after方法");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
<!-- 配置bean後處理器
這個bean後處理器會在bean實例化後和初始化前後執行相應的方法
例如可以在bean初始化前後打印日誌
需要實現BeanPostProcessor接口
這樣spring容器在創建其他bean時會自動調用這個後處理器的相應方法
例如上面的springBean在實例化和初始化時就會調用LogBeanPostProcessor中的方法
這樣就可以在控制枱看到日誌輸出
這個bean後處理器必須配置在spring配置文件中,才能被spring容器識別和調用
這個bean後處理器將作用於當前配置文件中的所有bean
-->
<bean class="com.ali.bean.LogBeanPostProcessor" />
精細化分為10步
- 實例化bean
調用的是無參數的構造方法
- bean屬性賦值
執行set注入
-
檢查bean是否實現Aware相關接口(BeanNameAware, BeanClassLoaderAware, BeanFactoryAware),如果實現了,則調用這些接口相關的方法。
-
執行“Bean後處理器”的before方法
-
檢查bean是否實現InitializingBean接口,並調用接口方法
-
初始化bean
調用bean的init()方法,需要自己寫,自己配
-
執行“Bean後處理器”的after方法
-
使用bean
-
檢查bean是否實現了DisposableBean接口,並調用接口方法
-
銷燬bean
調用bean的destroy(),需要自己寫,自己配
spring容器只對singleton的bean進行完整的生命週期管理。
如果是prototype作用域的bean,spring容器只負責初始化完畢,等客户端程序一旦獲取到該bean後,spring容器就不再管理該對象的聲明週期了。
自己new的對象如何讓spring容器管理
使用DefaultListableBeanFactory類注入自己創建的對象。
public static void main(String[] args) {
User user = new User();
System.out.println(user);
// 將以上new的對象交給spring容器管理
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("userBean", user);
// 從spring容器中獲取
Object userBean = beanFactory.getBean("userBean");
System.out.println(userBean);
}
bean的循環依賴問題
bean的循環依賴:A對象中有B屬性。B對象中有A屬性。這種你依賴我,我依賴你的情況就是循環依賴。
singleton+setter模式
<!-- singleton+setter方式解決循環依賴-->
<!-- 通過setter方法注入依賴,可以解決循環依賴問題 -->
<!-- spring容器在創建bean時會先實例化bean對象,然後通過setter方法注入依賴-->
<!-- 這樣即使存在循環依賴,spring也能正確創建和注入bean-->
<bean id="husbandBean" class="com.ali.bean.Husband" >
<property name="name" value="Jack"/>
<property name="wife" ref="wifeBean"/>
</bean>
<bean id="wifeBean" class="com.ali.bean.Wife" >
<property name="name" value="Rose"/>
<property name="husband" ref="husbandBean"/>
</bean>
在這種模式(singleton+setter)下主要分為2個階段來解決:
1. 在spring容器加載的時候,實例化bean。只要其中任意一個bean實例化之後,馬上進行“曝光”【不等屬性賦值就曝光】
2. bean“曝光”後再進行賦值
prototype+setter模式
<!-- 在prototype+setter方式下無法解決循環依賴問題,會出現異常
因為prototype作用域下,spring容器不會緩存bean實例,每次獲取都會創建一個新的實例
這樣當husbandBean實例化時,wifeBean還沒有被創建,導致無法注入wifeBean
反之亦然,最終會導致循環依賴失敗,拋出異常
所以prototype作用域下不支持循環依賴
但是:當2個bean的scope不同時(其中任意一個是singleton)是可以的
例如下面的配置中,husbandBean是singleton作用域,wifeBean是prototype作用域
這樣在創建husbandBean時,wifeBean會被創建並注入
但是每次獲取wifeBean時,都會創建一個新的實例
這樣就避免了循環依賴的問題
因為singleton只會創建一次,而prototype每次獲取都會創建新的實例
所以這種組合方式是可行的-->
<bean id="husbandBean" class="com.ali.bean.Husband" scope="singleton">
<property name="name" value="Jack"/>
<property name="wife" ref="wifeBean"/>
</bean>
<bean id="wifeBean" class="com.ali.bean.Wife" scope="prototype">
<property name="name" value="Rose"/>
<property name="husband" ref="husbandBean"/>
</bean>