Spring原始碼之Bean例項化基本原理

建立Spring Bean例項化是Spring Bean生命週期的第一階段

Bean的生命週期主要有如下幾個步驟:

Spring原始碼之Bean例項化基本原理

「詳細介紹:Spring In Action是這樣講的:」

例項化Bean物件,這個時候Bean的物件是非常低階的,基本不能夠被我們使用,因為連最基本的屬性都沒有設定,可以理解為連Autowired註解都是沒有解析的;

填充屬性,當做完這一步,Bean物件基本是完整的了,可以理解為Autowired註解已經解析完畢,依賴注入完成了;

如果Bean實現了BeanNameAware介面,則呼叫setBeanName方法;

如果Bean實現了BeanClassLoaderAware介面,則呼叫setBeanClassLoader方法;

如果Bean實現了BeanFactoryAware介面,則呼叫setBeanFactory方法;

呼叫BeanPostProcessor的postProcessBeforeInitialization方法;

如果Bean實現了InitializingBean介面,呼叫afterPropertiesSet方法;

如果Bean定義了init-method方法,則呼叫Bean的init-method方法;

呼叫BeanPostProcessor的postProcessAfterInitialization方法;當進行到這一步,Bean已經被準備就緒了,一直停留在應用的上下文中,直到被銷燬;

如果應用的上下文被銷燬了,如果Bean實現了DisposableBean介面,則呼叫destroy方法,如果Bean定義了destory-method聲明瞭銷燬方法也會被呼叫。

在例項化Bean之前在BeanDefinition裡頭已經有了所有需要例項化時用到的元資料,接下來Spring只需要選擇合適的例項化方法以及策略即可。

「BeanDefinition」

Spring容器啟動的時候會定位我們的配置檔案,載入檔案,並解析成Bean的定義檔案BeanDefinition

Spring原始碼之Bean例項化基本原理

右邊的Map裡儲存這bean之間的依賴關係的定義BeanDefinition,比如OrderController依賴OrderService這種

例項化方法有兩大類分別是工廠方法和構造方法例項化,後者是最常見的。其中Spring預設的例項化方法就是無參建構函式例項化。

如我們在xml裡定義的以及用註解標識的bean都是透過預設例項化方法例項化的

例項化方法

「使靜態工廠方法例項化」

public class FactoryInstance { public FactoryInstance() { System。out。println(“instance by FactoryInstance”); }}複製程式碼

Spring原始碼之Bean例項化基本原理

public class MyBeanFactory { public static FactoryInstance getInstanceStatic(){ return new FactoryInstance(); }}複製程式碼

Spring原始碼之Bean例項化基本原理

<?xml version=“1。0” encoding=“UTF-8”?> 複製程式碼

Spring原始碼之Bean例項化基本原理

「使用例項工廠方法例項化」

public class MyBeanFactory { /** * 例項工廠建立bean例項 * * @return */ public FactoryInstance getInstance() { return new FactoryInstance(); }}複製程式碼

Spring原始碼之Bean例項化基本原理

<?xml version=“1。0” encoding=“UTF-8”?> <!—— 工廠例項 —— > 複製程式碼

Spring原始碼之Bean例項化基本原理

「使用無參建構函式例項化(預設的)」

public class ConstructorInstance { public ConstructorInstance() { System。out。println(“ConstructorInstance none args”); }}複製程式碼

Spring原始碼之Bean例項化基本原理

<?xml version=“1。0” encoding=“UTF-8”?> 複製程式碼

Spring原始碼之Bean例項化基本原理

「使用有參建構函式例項化」

public class ConstructorInstance { private String name; public ConstructorInstance(String name) { System。out。println(“ConstructorInstance with args”); this。name = name; } public String getName() { return name; } public void setName(String name) { this。name = name; }}複製程式碼

Spring原始碼之Bean例項化基本原理

<?xml version=“1。0” encoding=“UTF-8”?> 複製程式碼

Spring原始碼之Bean例項化基本原理

原始碼閱讀

直接來看看doCreateBean方法

具體實現在AbstractAutowireCapableBeanFactory類裡面。

Spring原始碼之Bean例項化基本原理

Spring原始碼之Bean例項化基本原理

我們這裡只需關注第一步建立bean例項的流程即可

instanceWrapper = createBeanInstance(beanName, mbd, args);複製程式碼

Spring原始碼之Bean例項化基本原理

Spring原始碼之Bean例項化基本原理

Spring原始碼之Bean例項化基本原理

上面程式碼就是spring 實現bean例項建立的核心程式碼。這一步主要根據BeanDefinition裡的元資料定義決定使用哪種例項化方法,主要有下面三種:

instantiateUsingFactoryMethod 工廠方法例項化的具體實現

autowireConstructor 有參建構函式例項化的具體實現

instantiateBean 預設例項化具體實現(無參建構函式)

「例項化策略(cglib or 反射)」

工廠方法的例項化手段沒有選擇策略直接用了反射實現的,所以這個例項化策略都是對於建構函式例項化而言的

下面選一個instantiateBean的實現來介紹

Spring原始碼之Bean例項化基本原理

Spring原始碼之Bean例項化基本原理

上面說到的兩建構函式例項化方法不管是哪一種都會選一個例項化策略進行,到底選哪一種策略也是根據BeanDefinition裡的定義決定的。

下面這一行程式碼就是選擇例項化策略的程式碼

beanInstance = getInstantiationStrategy()。instantiate(mbd, beanName, parent);複製程式碼

Spring原始碼之Bean例項化基本原理

「選擇使用反射還是cglib」

Spring原始碼之Bean例項化基本原理

Spring原始碼之Bean例項化基本原理

先判斷如果beanDefinition。getMethodOverrides()為空也就是使用者沒有使用replace或者lookup的配置方法,那麼直接使用反射的方式,簡單快捷

但是如果使用了這兩個特性,在直接使用反射的方式建立例項就不妥了,因為需要將這兩個配置提供的功能切入進去,所以就必須要使用動態代理的方式將包含兩個特性所對應的邏輯的攔截增強器設定進去,這樣才可以保證在呼叫方法的時候會被相應的攔截器增強,返回值為包含攔截器的代理例項——-Spring原始碼深度解析

複製程式碼

Spring原始碼之Bean例項化基本原理

如果使用了lookup或者replaced的配置的話會使用cglib,否則直接使用反射。

public static final String LOOKUP_METHOD_ELEMENT = “lookup-method”;public static final String REPLACED_METHOD_ELEMENT = “replaced-method”;

Spring原始碼之Bean例項化基本原理