簡述
這篇文章參照spring源碼來了解一下bean的創建過程,本文的內容我在學習時畫了一張圖流程圖,結合圖和源碼會比較直觀
BeanFactory
bean工廠,一個創建bean的地方,他的主要方法是getBean
,如果已經生產過就直接返回,如果沒有就生產后再返回
其中生產bean走得就是createBean
方法,也是本位主要要介紹的方法
同時為了可以支持個性化生產bean的過程,spring使用的bean工廠又支持添加bean后置處理器,并且多種類型,不同類型再bean生產的不同時期調用
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
用戶通過添加后置處理器可以再某一個特定的生命周期參與bean的創建過程
createBean
這里開始跟蹤createBean源碼,分析重點操作的方法,首先有一句
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
這里先走了resolveBeforeInstantiation
,如果有返回直接返回bean,后續所有代碼全部短路,那么就看一下resolveBeforeInstantiation
是干嘛
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// bean定義的beforeInstantiationResolved屬性是true
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// 如果有InstantiationAwareBeanPostProcessor類型的后置處理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 執行這些后置處理器(InstantiationAwareBeanPostProcessor)
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 如果創建出bean,再執行BeanPostProcessorsAfterInitialization后置處理器
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
總結就是這里開始執行InstantiationAwareBeanPostProcessor
類型的后置處理器postProcessBeforeInstantiation
方法,給用戶一個機會使用它來完全自定義創建bean,最終如果創建出來了,只執行一個postProcessAfterInitialization
類型的后置處理器(這個后置處理器是實例化之后執行的,不管通過哪種方式,最終都會執行)就反回了。
看spring的注釋是這么說的:Typically used to suppress default instantiation for specific target beans(通常用于抑制特定目標 bean 的默認實例化),也就是說用戶如果有些特殊的bean不想按工程創建的套路生產,可以使用這種后置處理器來按自己的套路生產bean(這里我不知道spring有什么場景會使用它,以后再說)
doCreateBean
一般情況下,用戶還是走工廠的套路去創建bean,所以當resolveBeforeInstantiation
返回null時,就開始按工廠的套路創建bean了,也就是doCreateBean方法
下面開始進入doCreateBean方法,還是只關注主干代碼,下面的代碼都是從源碼貼出,只是貼重點
1.createBeanInstance
instanceWrapper = createBeanInstance(beanName, mbd, args);
這一步開始實例化bean,注意實例化和初始化的區別,簡單實例化就是new,初始化就是執行一些初始化方法
這個方法也不用多說了,就是使用反射去創建對象(如果有構造方法注入這里還會更復雜,暫不討論)
2.applyMergedBeanDefinitionPostProcessors
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
執行MergedBeanDefinitionPostProcessor類型的后置處理器,傳出BeanDefinition,beanName,beanType,可以修改BeanDefinition或干點其他事
3.addSingletonFactory
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
添加三級緩存,對bean工廠三級緩存不懂得可以參考手寫Spring之BeanFactory(三級緩存),這里添加的是一個工廠方法,如果方法被執行(出現循環依賴),會執行SmartInstantiationAwareBeanPostProcessor
后置處理器(主要是應付代理,后面介紹)
4.populateBean
populateBean(beanName, mbd, instanceWrapper);
給bean填充屬性,這一步有很多重要子步驟
4.1 postProcessAfterInstantiation
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
這里也是執行InstantiationAwareBeanPostProcessor
的后置處理器,但與上面createBean
不同的是執行的是postProcessAfterInstantiation
方法,剛才那個postProcessBeforeInstantiation
返回的是object,如果有返回代表截斷了bean的生產套路自己生產,而這個postProcessAfterInstantiation
方法如果返回false也是return
,短路了整個populateBean方法,也就是按照自己的套路填充屬性(其實他倆的存在都是因為spring已經很多開放的后置處理器可以調整創建過程,但是不免會有些特殊情況,使用spring處理不來,name就可以使用這種短路的方式完全又用戶自己掌控創建過程,就好像我們做一個文章編寫的系統,給了各種title的輸入框,并且可以選擇,已經很靈活了,但是也不能覆蓋所有用戶需求,那就給你個選擇,你可以按我們的套路編輯文章,也可以選擇使用富文本,愛怎么寫怎么寫)
4.2 pvs
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
這里獲取bean定義中指定的需要填充的屬性,后續還可以加,最終一起填充
4.3 autowireByName | autowireByType
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
獲取bean定義的依賴注入模式,然后調用autowireByName
或autowireByType
完成依賴注入
這種依賴注入是bean工廠提供的一種實現依賴注入的功能,但我們平時使用的注解形式依賴注入@Autowired
并不是使用這個功能,而是使用下面的4.4
這里如果有依賴注入的屬性,并沒有實際調用對象的set去賦值,而是存到pvs,還是最終一起填充
4.4 postProcessProperties
// 再次查找InstantiationAwareBeanPostProcessor類型后置處理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 執行postProcessProperties方法
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 最終覆蓋pvs(其實是添加)
pvs = pvsToUse;
}
}
還是執行InstantiationAwareBeanPostProcessor
后置處理器,執行postProcessProperties
,用戶可以自定義要填充的屬性,并填充到pvs,@Autowired
形式的注入就是寫了一個這個后置處理器來實現的,一會單獨說
4.5 applyPropertyValues
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
如果pvs(要填充的屬性)不為空,執行填充(通過反射去set屬性值)
這里總結一下pvs數據的來源: 1.bean定義里自帶的(4.2) 2.通過bean定義的resolvedAutowireMode
去autowire的(4.3) 3.通過后置處理器返回的(4.4)
5.initializeBean
exposedObject = initializeBean(beanName, exposedObject, mbd);
初始化bean,也就是執行初始化方法什么的,進去看看
5.1 invokeAwareMethods
invokeAwareMethods(beanName, bean);
執行aware方法,這個aware翻譯成中文就是感知,其實他的作用也挺簡單,就是有的bean用戶想讓產品用有工廠的聯系方式(beanFactory的引用),bean在工廠中的名字(BeanName),類加載器(BeanClassLoader),只要你的bean繼承了對應的Aware接口,就會給你提供這些信息,比如繼承了BeanFactoryAware
,再invokeAwareMethods
時就會執行setBeanFactory
方法并把BeanFactory傳出來,至于bean愛保存還是拿著干什么隨意。
有三種aware:
- BeanNameAware 可以獲取到BeanName
- BeanClassLoaderAware 可以獲取到BeanClassLoader
- BeanFactoryAware 可以獲取到BeanFactory
5.2 applyBeanPostProcessorsBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
執行所有后置處理器的postProcessBeforeInitialization
方法,這一步可以獲取到這個階段的bean(wrappedBean里包含,初始化前),并可以返回一個新的bean覆蓋原來的bean,比如創建代理
5.3 invokeInitMethods
執行初始化方法,也就是@PostConstruct注解的方法
5.4 applyBeanPostProcessorsAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
執行所有后置處理器的postProcessBeforeInitialization
方法,這一步可以獲取到這個階段的bean(wrappedBean里包含,初始化后),并可以返回一個新的bean覆蓋原來的bean,比如創建代理,spring的AOP實現就是再這里加了后置處理用代理bean覆蓋了原bean
6.getSingleton
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
這一步主要看看有沒有提前暴露,如果有則替換當前的bean,主要解決循環依賴和AOP,一會將循環依賴細說
7.registerDisposableBeanIfNecessary
registerDisposableBeanIfNecessary(beanName, bean, mbd);
這步記錄bean,以便銷毀時使用
到此整個創建過程就結束了,這是beanFactory創建bean的整個過程,并預留了很多鉤子(后置處理器)可以實現各種特殊要求,spring的依賴注入和AOP就是通過添加后置處理器來實現的,流程圖
@Autowired(AutowiredAnnotationBeanPostProcessor)
我們平時要實現依賴注入最常用的就是@Autowired
,意思要填充屬性
通過對bean創建過程代碼的分析并沒有依靠@Autowired
填充屬性的代碼,但是有通過后置處理器填充屬性的邏輯,不錯,@Autowired就是依靠一個特定的后置處理器完成屬性填充的。
這個后置處理器就是AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor
繼承了MergedBeanDefinitionPostProcessor
和InstantiationAwareBeanPostProcessor
(其它的先忽略)
看看分別的實現,做了什么
postProcessMergedBeanDefinition
這個方法是在實例化之后調用
看看該后置處理器的實現
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
就不細說了,總結就是掃描bean的@Autowired和@Value注解,并通過beanName緩存起來
postProcessProperties
這個實在填充屬性時調用
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
metadata.inject(bean, beanName, pvs);
return pvs;
}
代碼就是獲取上一步的緩存,然后給bean設置屬性(我記得這一步是直接給bean就設置屬性了,pvs并沒有變,但我覺得應該先設置pvs,最后統一在applyPropertyValues的時候實際填充屬性,這個可以自己看代碼去確定)
總之,通過這兩步,1.掃描@Autowired存緩存 2.根據緩存依賴注入 就完成了@Autowired
的功能
@AOP(AbstractAutoProxyCreator)
AOP功能實現的方式同樣也是使用后置處理器,即AbstractAutoProxyCreator
,是一個抽象類,但主要的方法都在這里,所以就介紹他
主要實現了SmartInstantiationAwareBeanPostProcessor
和BeanPostProcessor
(其它先忽略)
看看分別的實現,做了什么
getEarlyBeanReference
這一步調用是出現循環依賴時調用
看看實現
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 根據beanName和class生成一個key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 使用key存儲bean
this.earlyProxyReferences.put(cacheKey, bean);
// wrapIfNecessary
return wrapIfNecessary(bean, beanName, cacheKey);
}
主要是按特定的key存了一個緩存,然后執行wrapIfNecessary(其實就是如果設置了代理則創建代理)
如果這一步創建了代理,容器中就已經存放了當前bean的代理,所以bean的創建過程最后如果getSingleton
獲取到了bean代表提前暴露了,創建了代理所以最終需要返回這個代理的bean對象,也就是
exposedObject = earlySingletonReference;
postProcessAfterInitialization
初始化結束之后執行
實現
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
這里的邏輯是之前走沒走getEarlyBeanReference
(即有沒有提前暴露),如果沒走,執行wrapIfNecessary
,這里不懂的可以看看手寫Spring之BeanFactory(三級緩存)這篇文章
wrapIfNecessary
兩個方法都有用到wrapIfNecessary
,里面的代碼就不貼了,最重要的是一句
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
即是創建代理,里面的內容就是創建代理的過程,可以參照我之前的Spring AOP系列文章
最后
spring支持注解依賴注入和AOP,但beanFactory本身不能實現這些功能,而是通過后置處理器方式實現的,那是誰把這些后置處理器交給BeanFactory的吶?答案就是ApplicationContext
over~