深入理解Spring 之 Spring 進階開發必知必會 之 Spring 擴充套件介面

weixin_34075551發表於2017-12-13
4236553-0b7501acaaed2f97.jpg

# 前言

我們在前幾篇文章中已經深入瞭解了 Spring 的 IOC 機制和 AOP 機制,在閱讀原始碼的同時,樓主對 Spring 中設計模式的運用可以說五體投地,還有我們還知道更重要的一點就是:Spring 留給了我們大量的擴充套件介面供開發者去自定義自己的功能,甚至於 AOP 就是在 Spring 預留的擴充套件介面中實現的,意思是隻要基於 Spring IOC,遵守 Spring 對擴充套件介面的約定,那麼就能實現自己想要的功能。可見 IOC 的強大,那麼。今天我們就將 Spring 留給我們的介面拿出來說一說。而我們的標題是Spring 進階開發,為什麼這麼說,如果說只是簡單的使用 Spring 中的bean,那麼只是Spring的初級開發者。如何精通Spring 就看有沒有掌握好Spring留給我們的這些擴充套件介面,以及如何使用他們。

我們今天主要講述以下幾個介面,如有遺漏,請指出:

  1. FactroyBean 我們熟悉的AOP基礎bean
  2. BeanPostProcess 在每個bena初始化成前後做操作。
  3. InstantiationAwareBeanPostProcessor 在Bean例項化前後做一些操作。
  4. BeanNameAware、ApplicationContextAware 和 BeanFactoryAware 針對bean工廠,可以獲取上下文,可以獲取當前bena的id。
  5. BeanFactoryPostProcessor Spring允許在Bean建立之前,讀取Bean的元屬性,並根據自己的需求對元屬性進行改變,比如將Bean的scope從singleton改變為prototype。
  6. InitialingBean 在屬性設定完畢後做一些自定義操作 DisposableBean 在關閉容器前做一些操作。

1. FactroyBean 我們熟悉的AOP基礎bean

這個Bean 我們再屬性不過,我們再學習 AOP 的時候,知道 XML 方式的 AOP 就是通過該介面實現的。我們複習以下該介面的結構。

public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
    boolean isSingleton();
}

該介面定義了3個方法,獲取bean例項,獲取bean型別,是否是單例。Spring 在 IOC 初始化的時候,一般的Bean都是直接呼叫構造方法,而如果該Bean實現了FactoryBean 介面,則會呼叫該Bean的 getObject 方法獲取bean,這也是Spring 使用此介面構造AOP的原因。在 IOC 呼叫此方法的時候,返回一個代理,完成AOP代理的建立。

我們做個測試:定義一個FactoryBean,重寫他的 getObject 方法:

4236553-0690073c1a323270.png

測試類中呼叫:

4236553-420c6f81201b7dda.png

注意:此時返回的已經是 AOP 型別的Bean,因為我們在 getObject 返回到是 new Aop(),驗證了我們之前說的。使用該介面,能夠為我們做很多有趣的事情。就靠你來想象了。

2. BeanPostProcess 在每個bean初始化成前後做操作。

該介面我們應該也非常的熟悉,還記的我們的註解配置的AOP是如何實現的。就是間接實現了該介面。在 IOC 初始化的時候,會呼叫的該介面的後置處理方法。我們看看該介面定義:

public interface BeanPostProcessor {

    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

一個是前置方法,一個是後置方法,註解方式的AOP的實現就是在 postProcessAfterInitialization 方法中實現的。我們寫一個測試類,看看結果是什麼?

4236553-d5b8cb9a8e309d0d.png

我們在Bean 初始化之前後之後都列印以下該Bean的名稱,那麼執行結果是什麼呢?下面是SpringBoot 啟動後的一部分日誌:

4236553-2994bfb922c69ae6.png

可以看到我們專案中所有的Bean在初始化的時候都呼叫該方法。因此,我們在以後的開發中就可以做一些自定義的事情。

3. InstantiationAwareBeanPostProcessor 在Bean例項化前後做一些操作。

這個介面實際上我們也是非常的熟悉,該介面在我們剖析註解配置AOP的時候是我們的老朋友,實際上,註解配置的AOP是間接實現 BeanPostProcess 介面的,而 InstantiationAwareBeanPostProcessor 就是繼承該介面的。我們看看他的繼承圖譜:

4236553-74dcb5b9177f71b9.png

可以看到該介面在繼承的基礎上又增加了3個方法,增加了擴充套件bean的功能。我們寫個 Demo 測試一下:

4236553-29ddb24f49ffece8.png

可以看到,需要實現 5 個方法,其中2個方法是 BeanPostProcess 介面定義的方法:在bean初始化的前後執行,而 InstantiationAwareBeanPostProcessor 則新增了 3 個方法,分別是 postProcessBeforeInstantiation (例項化之前),postProcessAfterInstantiation (例項化之後),postProcessPropertyValues (在處理Bean屬性之前),開發者可以在這三個方法中新增自定義邏輯,比如AOP。我們看看執行結果。

4236553-d96008103fc9befc.png

可以看到,所有的Bean在IOC的時候都執行了我們的方法,其中例項化在初始化之前執行,這個順序對我們使用該介面是很重要的,千萬不要弄混。

4. BeanNameAware、ApplicationContextAware 和 BeanFactoryAware 針對bean工廠,可以獲取上下文,可以獲取當前bena的id。

這三個介面的功能其中都一樣,我們看看他們的繼承圖譜就知道了:

4236553-f5fb19b0b26f3952.png

可以看到,這三個介面都繼承自 Aware 介面,並分別定義了自己的介面定義方法。實現這些介面就能得到Spring的Bean 工廠。從而呼叫getBean方法獲取Bean。很多專案中都使用此介面做了Spring的工具類。比如可以像這麼使用:

4236553-244d60d8fba15307.png

我們寫了一個測試類,然後看以下執行結果:

4236553-d92ed33522990841.png

執行結果:

4236553-dee8507b0239efd6.png

可以看到,在IOC的過程中,該Bean的三個方法都被執行,我們就可以獲取到容器,從而可以做很多自定義的額事情。

5. BeanFactoryPostProcessor Spring允許在Bean建立之前,讀取Bean的元屬性,並根據自己的需求對元屬性進行改變,比如將Bean的scope從singleton改變為prototype。

我們看看該介面的定義:

4236553-68faef012c4f21e9.png

只定義了一個方法,該方法註釋:在它的標準初始化之後修改應用程式上下文的內部bean工廠。所有的bean定義都已經載入了,但是還沒有例項化bean。這允許覆蓋或新增屬性,甚至是對初始化bean的屬性。引數是什麼呢?應用程式上下文所使用的bean工廠。也就是說,我們可以獲取某個Bean的定義,然後修改該Bean的定義:比如下面這樣:

4236553-181c10f1798c536a.png

我們看看執行結果:

4236553-b0b2ed0df773fd6d.png

我們將成功的單例的Bean改成了多例。

6. InitialingBean 在屬性設定完畢後做一些自定義操作。 DisposableBean 在關閉容器前做一些操作。

我們寫以下demo 看看是如何執行的:

實現這兩個介面:

4236553-f8c60f69a5d149a3.png

啟動類:

4236553-9e5c0949f89c1dff.png

在執行啟動類之後,就會關閉容器。退出虛擬機器,我們看看執行結果:

4236553-89fe607165ba9df0.png

在執行Set 屬性方法後,立即執行 afterPropertiesSet 方法,因此,我們就可以在該方法中做一些事情,然後在執行 System.exit(0) 後,執行 destroy 方法,我們也可以在該方法中執行一些邏輯。

7 總結

我們瞭解了 Spring 留給我們的擴充套件介面,以提高我們使用 Spring 的水平,在以後的業務中,也就可以基於 Spring 做一些除了簡單的注入這種基本功能之外的功能。同時,我們也發現,Spring 的擴充套件性非常的高,符合設計模式中的開閉原則,對修改關閉,對擴充套件開放,實現這些的基礎就是 Spring 的 IOC,IOC 可以說是 Spring 的核心, 在 IOC 的過程中,對預定義的介面做了很多的預留工作。這讓其他框架與 Spring 的組合變得更加的簡單,我們在以後的開發工作中也可以借鑑 Spring 的思想,讓程式更加的優美。

相關文章