javascript
天天用 Spring,bean 实例化原理你懂吗?
來源:小小木的博客
www.cnblogs.com/wyc1994666/p/10650480.html
本次主要想寫spring bean的實例化相關的內容。創建spring bean 實例是spring bean 生命周期的第一階段。
bean 的生命周期主要有如下幾個步驟:
-
創建bean的實例
-
給實例化出來的bean填充屬性
-
初始化bean
-
通過IOC容器使用bean
-
容器關閉時銷毀bean
在實例化bean之前在BeanDefinition里頭已經有了所有需要實例化時用到的元數據,接下來spring 只需要選擇合適的實例化方法以及策略即可。實例化方法有兩大類分別是工廠方法和構造方法實例化,后者是最常見的。
spring默認的實例化方法就是無參構造函數實例化。
如我們在xml里定義的?<bean id="xxx" class="yyy"/>?以及用注解標識的bean都是通過默認實例化方法實例化的。
-
兩種實例化方法(構造函數 和 工廠方法)
-
源碼閱讀
-
實例化策略(cglib or 反射)
兩種實例化方
使用適當的實例化方法為指定的bean創建新實例:工廠方法,構造函數實例化。
代碼演示
啟動容器時會實例化所有注冊的bean(lazy-init懶加載的bean除外),對于所有單例非懶加載的bean來說當從容器里獲取bean(getBean(String name))的時候不會觸發,實例化階段,而是直接從緩存獲取已準備好的bean,而生成bean的時機則是下面這行代碼運行時觸發的。
@Test public?void?testBeanInstance(){????????//?啟動容器ApplicationContext?context?=?new?ClassPathXmlApplicationContext("spring-beans.xml"); }一 使用工廠方法實例化(很少用)
1.靜態工廠方法
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>輸出結果為:
instance by FactoryInstance
2.實例工廠方法
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>輸出結果為:
instance by FactoryInstance
二 使用構造函數實例化(無參構造函數 & 有參構造函數)
1.無參構造函數實例化(默認的)
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>輸出結果為:
ConstructorInstance none args
1.有參構造函數實例化
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>輸出結果為:
ConstructorInstance with args
源碼閱讀
下面這段是 有關spring bean生命周期的代碼,也是我們本次要討論的bean 實例化的入口。bean 為什么默認單例?
doCreateBean方法具體實現在doCreateBeanAbstractAutowireCapableBeanFactory類,感興趣的朋友可以進去看看調用鏈。
protected?Object?doCreateBean(final?String?beanName,?final?RootBeanDefinition?mbd,?final?Object[]?args)?{//第一步?創建bean實例?還未進行屬性填充和各種特性的初始化BeanWrapper?instanceWrapper?=?null;if?(instanceWrapper?==?null)?{instanceWrapper?=?createBeanInstance(beanName,?mbd,?args);}final?Object?bean?=?(instanceWrapper?!=?null???instanceWrapper.getWrappedInstance()?:?null);Class<?>?beanType?=?(instanceWrapper?!=?null???instanceWrapper.getWrappedClass()?:?null);Object?exposedObject?=?bean;try?{//?第二步?進行屬性填充populateBean(beanName,?mbd,?instanceWrapper);if?(exposedObject?!=?null)?{//?第三步?初始化bean?執行初始化方法exposedObject?=?initializeBean(beanName,?exposedObject,?mbd);}}catch?(Throwable?ex)?{//??拋相應的異常}//?Register?bean?as?disposable.try?{registerDisposableBeanIfNecessary(beanName,?bean,?mbd);}catch?(BeanDefinitionValidationException?ex)?{throw?new?BeanCreationException(mbd.getResourceDescription(),?beanName,?"Invalid?destruction?signature",?ex);}return?exposedObject; }我們這里只需關注第一步創建bean實例的流程即可
instanceWrapper = createBeanInstance(beanName, mbd, args);
上面代碼就是spring 實現bean實例創建的核心代碼。這一步主要根據BeanDefinition里的元數據定義決定使用哪種實例化方法,主要有下面三種:
-
instantiateUsingFactoryMethod 工廠方法實例化的具體實現
-
autowireConstructor 有參構造函數實例化的具體實現
-
instantiateBean 默認實例化具體實現(無參構造函數)
實例化策略(cglib or 反射)
工廠方法的實例化手段沒有選擇策略直接用了發射實現的
實例化策略都是對于構造函數實例化而言的
上面說到的兩構造函數實例化方法不管是哪一種都會選一個實例化策略進行,到底選哪一種策略也是根據BeanDefinition里的定義決定的。
beanInstance?=?getInstantiationStrategy().instantiate(mbd,?beanName,?parent);上面這一行代碼就是選擇實例化策略的代碼,進入到上面兩種方法的實現之后發現都有這段代碼。
下面選一個instantiateBean的實現來介紹
protected?BeanWrapper?instantiateBean(final?String?beanName,?final?RootBeanDefinition?mbd)?{try?{Object?beanInstance;final?BeanFactory?parent?=?this;if?(System.getSecurityManager()?!=?null)?{beanInstance?=?AccessController.doPrivileged(new?PrivilegedAction<Object>()?{@Overridepublic?Object?run()?{return?getInstantiationStrategy().instantiate(mbd,?beanName,?parent);}},?getAccessControlContext());}else?{//?在這里選擇一種策略進行實例化beanInstance?=?getInstantiationStrategy().instantiate(mbd,?beanName,?parent);}BeanWrapper?bw?=?new?BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return?bw;}catch?(Throwable?ex)?{throw?new?BeanCreationException(mbd.getResourceDescription(),?beanName,?"Instantiation?of?bean?failed",?ex);} }選擇使用反射還是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,否則直接使用反射。
具體lookup-method和replaced-method的用法可以查閱相關資料。
由于篇幅省略了部分代碼。
總結
以上是生活随笔為你收集整理的天天用 Spring,bean 实例化原理你懂吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tomcat 架构原理到架构设计,写得非
- 下一篇: 这次被问懵了!搞定了这些SQL优化技巧,