1. 程式人生 > >Spring IOC 初始化順序問題

Spring IOC 初始化順序問題

今天在群裡面看到了一個很有趣的問題。那就是Spring IOC的執行順序問題。知道IOC初始化順序的朋友都應該知道,Spring IOC的執行順序:

  1. 先執行BeanPostProcessor.postProcessBeforeInitialization方法。
  2. 然後執行InitializingBean.afterPropertiesSet方法。
  3. 最後再執行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方法。

這裡寫圖片描述

其實看到這裡大家就應該明白了。

  1. 當註冊BeanPostProccessor的時候會呼叫getBean方法,那個時候BeanPostProcess並不生效,所以只會呼叫InitializingBean的afterPropertiesSet方法,
  2. 然後再註冊了這個BeanPostProcessor就會呼叫它的postProcessBeforeInitialization和postProcessAfterInitialization。
  3. 當你再次使用getBean方法呼叫的時候這個時候,Spring容器裡面已經存在了這個Bean物件,它就會直接從容器裡面拿,就不需要走到後面的例項化bean,所以不會出現InitializingBean的方法,也不會出現BeanPostProcessor的處理方法。

3、問題的思考

細想一下,其實我們這個Bean這個類即實現了BeanPostProcessor,又實現了InitializingBean。當我們實現BeanPostProcessor的時候是希望這個物件是作為Spring IOC容器功能的擴充套件,而實現InitializingBean是把這個物件當成一個普通Bean。明顯這個物件在這裡是有二個角色。這裡就涉及到面向物件設計的一個重要的原則 – 單一職責原則。所以我們在設計功能的時候,一定要考慮面向物件設計的原則。