手寫模擬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實例進行預處理擴展。 通過上述代碼的實現效果如下: 源代碼:

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

7 總結

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