手寫模擬Spring底層原理-Bean的建立與獲取

語言: CN / TW / HK

作者:京東物流 張鼎元

1 引言

大家好,相信大家對Spring的底層原理都有一定的瞭解,這裡我們會針對Spring底層原理,在海量的Spring原始碼中進行抽絲剝繭手動實現一個Spring簡易版本,來促進我們對Spring架構有個更深的理解,對Spring的常用功能進行手寫模擬實現。

2 啟動Spring

針對Bean的建立和獲取功能,我們來進行功能的實

首先我們建立JdApplicationContext類做為Spring啟動類,實現bean的載入和獲取功能。

UserService和OrderService類作為Bean的實現類,通過JdApplicationContext類中的getBean方法獲取到前面兩個類的實現。

  • App為啟動測試類
  • AppConfig為啟動配置類

注:下面的程式碼會順著內容講解逐步完成

首先建立App類做為入口,測試Spring功能。通過初始化JdApplicationContext類,動態載入bean例項。 通過getBean方法獲取bean例項。

建立JdApplicationContext類,提供獲取Bean例項方法,通過建構函式動態初始化bean例項。

3 掃描類路徑並快取BeanDefinition資料

在JdApplicationContext類初始化的時候,通過AppConfig配置類獲取類的掃描路徑,在掃描路徑下,找到需要建立Bean的類,通過標註Component註解的類識別需要建立的Bean。

通過Component註解識別出的類,進行封裝成BeanDefinition. 再快取到beanDefinitionMap記憶體中。

上述的程式碼中,我們發現建立BeanDefinition類時,封裝了class類,beanName,scope三個主要屬性。用於建立bean的時候,提供class類進行初始化和屬性的注入,建立單例類或原型類提供資料依據。

4 初始化Bean和依賴注入

接下來,在上面的掃描操作完成後,所有待初始化的bean資料儲存beanDefinitionMap中。我們只需要遍歷beanDefinitionMap資料進行逐個初始化和屬性的注入。

上述程式碼中,對bean進行初始化時候,從beanDefinition中獲取要初始化的class,通過反射機構進行無參初始化。

初始化完成後,再對有Autowired註解的屬性進行依賴注入,Autowired註解沒有傳遞value值時預設取屬性名稱作為beanName,通過getBean方法獲取bean例項。

getBean方法會通過beanName,從beanDefinitionMap中取得beanDefinition資料。通過beanDefinition確認該bean為單例類原型類

如果為原型類,直接呼叫createBean方法進行bean初始化。

如果為單例類,首先從singletonBeanMap快取中獲取bean例項。如果未獲取到,呼叫createBean方法獲取bean例項,同時將已建立bean例項快取到singletonBeanMap快取中。

此時,在上述的功能中,依賴注入簡易版本已實現。同時我們注意到UserService和OrderService可能會產生迴圈依賴的問題,在這裡如何解決呢?

問題程式碼如下 : 上圖就是迴圈依賴問題程式碼導致的異常。重複建立bean進入死迴圈。

在初始化bean和屬性注入之間,我們可以增加二級快取作為突破口,解決死迴圈問題。

userService初始化後,需要注入orderService,通過getBean方法獲取,因為orderService沒有在singletonBeanMap快取中,也需要初始化並注入userService屬性, 同時userService還在初始化過程中,不能快取到singletonBeanMap快取中。造成彼此迴圈等待屬性的注入。為解決此問題,我們只需要設立初始化過程中快取到creatingBeanMap中,在userService初始化過後,未進行屬性注入前快取到creatingBeanMap中,userService需要的orderService屬性在建立bean例項過程中,優先從creatingBeanMap快取中得到userService例項,來完成bean例項的建立過程。orderService完成bean例項建立後,userService也相應的完成例項建立。

5 實現InitializingBean介面

在createBean過程中,我們可以對外提供初始化擴充套件介面InitializingBean介面。只要實現該介面,我們就可以針對bean的初始化進行擴充套件功能實現。 ![]

6 實現BeanPostProcessor介面模擬AOP

首先建立BeanPostProcessor介面,作為所有bean例項的對外擴充套件介面建立BeanPostProcessor介面實現類,模擬AOP功能,指定userService類進行切面。 在掃描類的時候,將已實現BeanPostProcessor介面類快取到beanPostProcessorList中。 通過上面的掃描,beanPostProcessorList已快取所有的BeanPostProcessor實現類。在createBean的時候,對已建立的bean例項進行預處理擴充套件。 通過上述程式碼的實現效果如下: 原始碼:

https://3.cn/109Aj-Zok

7 總結

在上述的講解中,我們對Spring底層原理進行簡單的實現,通過對類的掃描,註解標識的判斷,beanDefinition的定義和快取。通過反射和代理進行bean例項的建立和擴充套件。相信大家也看出來在實現過程中,有很多地方需要改進,還可以繼續擴充套件Spring很多其它功能。例如擴充套件beanDefinition的註冊,引入Bean工廠,延遲載入等。