Spring IOC 初始化順序問題
今天在群裡面看到了一個很有趣的問題。那就是Spring IOC的執行順序問題。知道IOC初始化順序的朋友都應該知道,Spring IOC的執行順序:
- 先執行BeanPostProcessor.postProcessBeforeInitialization方法。
- 然後執行InitializingBean.afterPropertiesSet方法。
- 最後再執行BeanPostProcessor.postProcessAfterInitialization方法。
也就是說InitializingBean.afterPropertiesSet的執行順序是在BeanPostProcessor的before和after方法之間執行。
但是群裡面的那個朋友遇到了這樣的問題。就是InitializingBean.afterPropertiesSet的執行順序是在BeanPostProcessor的before和after方法之前執行。那麼這個是不是就是Spring IOC的生命週期相矛盾呢?
首先我再現一下這個問題。
1、問題復現
Bean類同時實現BeanPostProcessor與InitializingBean.
Bean.java
@Component
public class Bean implements BeanPostProcessor, InitializingBean {
public void afterPropertiesSet() throws Exception {
System.out.println("-----------------------invoke InitializingBean method afterPropertiesSet");
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------------------invoke BeanPostProcessor method postProcessBeforeInitialization" );
return null;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------------------invoke BeanPostProcessor method postProcessAfterInitialization");
return null;
}
}
測試類,用於載入配置的Bean檔案。
Test.java
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(Bean.class);
configApplicationContext.getBean(Bean.class);
}
}
執行結果:
在圖片中我們可以看到:
InitializingBean.afterPropertiesSet先於BeanPostProcessor.postProcessBeforeInitialization執行。這就和Spring IOC的生命週期相悖。
那麼下面就來分析一下為什麼會出現這種情況:
2、問題的來源
我們知道,當使用BeanPostProcessor的時候,Spring會先註冊這個物件。要註冊這個對應其實就是把它納入到Spring容器的管理中,就會呼叫getBean方法。
其實看到這裡大家就應該明白了。
- 當註冊BeanPostProccessor的時候會呼叫getBean方法,那個時候BeanPostProcess並不生效,所以只會呼叫InitializingBean的afterPropertiesSet方法,
- 然後再註冊了這個BeanPostProcessor就會呼叫它的postProcessBeforeInitialization和postProcessAfterInitialization。
- 當你再次使用getBean方法呼叫的時候這個時候,Spring容器裡面已經存在了這個Bean物件,它就會直接從容器裡面拿,就不需要走到後面的例項化bean,所以不會出現InitializingBean的方法,也不會出現BeanPostProcessor的處理方法。
3、問題的思考
細想一下,其實我們這個Bean這個類即實現了BeanPostProcessor,又實現了InitializingBean。當我們實現BeanPostProcessor的時候是希望這個物件是作為Spring IOC容器功能的擴充套件,而實現InitializingBean是把這個物件當成一個普通Bean。明顯這個物件在這裡是有二個角色。這裡就涉及到面向物件設計的一個重要的原則 – 單一職責原則。所以我們在設計功能的時候,一定要考慮面向物件設計的原則。