Spring源碼之Bean實例化基本原理
創建Spring Bean實例化是Spring Bean生命周期的第一階段
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
右邊的Map里存儲這bean之間的依賴關系的定義BeanDefinition,比如OrderController依賴OrderService這種
實例化方法有兩大類分別是工廠方法和構造方法實例化,后者是最常見的。其中Spring默認的實例化方法就是無參構造函數實例化。
如我們在xml里定義的以及用注解標識的bean都是通過默認實例化方法實例化的
實例化方法
「使靜態工廠方法實例化」
- public class FactoryInstance {
- public FactoryInstance() {
- System.out.println("instance by FactoryInstance");
- }
- }
- public class MyBeanFactory {
- public static FactoryInstance getInstanceStatic(){
- return new FactoryInstance();
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <bean id="factoryInstance" class="spring.service.instance.MyBeanFactory"
- factory-method="getInstanceStatic"/>
- </beans>
「使用實例工廠方法實例化」
- public class MyBeanFactory {
- /**
- * 實例工廠創建bean實例
- *
- * @return
- */
- public FactoryInstance getInstance() {
- return new FactoryInstance();
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <!-- 工廠實例 -- >
- <bean id="myBeanFactory" class="MyBeanFactory"/>
- <bean id="factoryInstance" factory-bean="myBeanFactory" factory-method="getInstance"/>
- </beans>
「使用無參構造函數實例化(默認的)」
- public class ConstructorInstance {
- public ConstructorInstance() {
- System.out.println("ConstructorInstance none args");
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance"/>
- </beans>
「使用有參構造函數實例化」
- 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;
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance">
- <constructor-arg index="0" name="name" value="test constructor with args"/>
- </bean>
- </beans>
源碼閱讀
直接來看看doCreateBean方法
具體實現在AbstractAutowireCapableBeanFactory類里面。
我們這里只需關注第一步創建bean實例的流程即可
- instanceWrapper = createBeanInstance(beanName, mbd, args);
上面代碼就是spring 實現bean實例創建的核心代碼。這一步主要根據BeanDefinition里的元數據定義決定使用哪種實例化方法,主要有下面三種:
- instantiateUsingFactoryMethod 工廠方法實例化的具體實現
- autowireConstructor 有參構造函數實例化的具體實現
- instantiateBean 默認實例化具體實現(無參構造函數)
「實例化策略(cglib or 反射)」
❝工廠方法的實例化手段沒有選擇策略直接用了反射實現的,所以這個實例化策略都是對于構造函數實例化而言的❞
下面選一個instantiateBean的實現來介紹
上面說到的兩構造函數實例化方法不管是哪一種都會選一個實例化策略進行,到底選哪一種策略也是根據BeanDefinition里的定義決定的。
下面這一行代碼就是選擇實例化策略的代碼
- beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
「選擇使用反射還是cglib」
先判斷如果beanDefinition.getMethodOverrides()為空也就是用戶沒有使用replace或者lookup的配置方法,那么直接使用反射的方式,簡單快捷
但是如果使用了這兩個特性,在直接使用反射的方式創建實例就不妥了,因為需要將這兩個配置提供的功能切入進去,所以就必須要使用動態代理的方式將包含兩個特性所對應的邏輯的攔截增強器設置進去,這樣才可以保證在調用方法的時候會被相應的攔截器增強,返回值為包含攔截器的代理實例-----Spring源碼深度解析
- <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance" >
- <lookup-method name="getName" bean="xxx"/>
- <replaced-method name="getName" replacer="yyy"/>
- </bean>
如果使用了lookup或者replaced的配置的話會使用cglib,否則直接使用反射。
- public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";
- public static final String REPLACED_METHOD_ELEMENT = "replaced-method";
覺得不錯,點個贊再走吧,謝謝
參考:
Spring源碼深度解析
Spring In Action
https://url.ms/owy8p
本文轉載自微信公眾號「月伴飛魚」,可以通過以下二維碼關注。轉載本文請聯系月伴飛魚公眾號。