1.前言
大致分析了下Spring的getBean過程,但主要關注doCreateBean。
2.整體流程
調用鏈:preInstantiateSingletons->getBean->doGetBean->getSingleton-> singletonFactory.getObject()->createBean->doCreateBean
圖中,需要特別注意getBean
、createBean
、createBeanInstance
、populateBean
、initializeBean
。
3.preInstantiateSingletons 提前初始化非lazy的單實例
由SpringIOC源碼學習總結可知,在Spring容器refresh的階段會調用finishBeanFactoryInitialization->preInstantiateSingletons,然後提前實例化非lazy的單實例。
3.1 getBean 得到/創建bean
調用鏈:createBean->doGetBean->getSingleton
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//doGetBean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
3.2 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
獲得單實例
調用鏈:getSingleton->singletonFactory.getObject()->createBean
- 先嚐試中
singletonObjects
拿到Spring已經緩存的bean實例。 - 標記該bean【正創建中】
- 調用
singletonFactory.getObject()
->createBean
創建bean。 - 添加到緩存。
- 去掉【正創建中】標記。
- 添加到緩存。
getSingleton源碼
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//標記爲該bean【正在創建】
beforeSingletonCreation(beanName);
...
//創建bean,重點關注
singletonObject = singletonFactory.getObject();
...
//添加到緩存
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}finally {
...
//去除 【正在創建】 的標記
afterSingletonCreation(beanName);
}
3.2.1 createBean`創建bean
調用鏈:createBean->doCreateBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
RootBeanDefinition mbdToUse = mbd;
//從BeanDefinition中取出Class信息
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
//爲bean設置<bean>標籤中的<replaced-method>方法。實現方法重載
mbdToUse.prepareMethodOverrides();
...
//有機會創建代理對象,暫不理會這裏
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
...
//創建bean實例, 重點關注
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}
3.3 getObjectForBeanInstance 處理FactoryBean
1.如果該bean是普通bean,則直接返回。如果該bean是FactoryBean,且getBean("&id")形式來獲取,則返回該bean.
2.否則是需要取FactoryBean#getObject
對應的實例。因此調用該bean的getObject方法返回實例bean,並放入factoryBeanObjectCache
緩存。
關於FactoryBean可查看FactoryBean的作用
4.doCreateBean(beanName, mbdToUse, args)
終於到了今天的主角doCreateBean
。
這裏就不貼代碼了, 太多了。需要看源碼直接看AbstractAutowireCapableBeanFactory#doCreateBean
直接看下流程圖:
流程:
- 創建實例:
createBeanInstance(beanName, mbd, args)
創建一個帶有bean實例的BeanWrapper
- 收集註解:通過
applyMergedBeanDefinitionPostProcessors
調用BeanPostProcessor收集@Resource、@Autowired、@PreConstruct等註解。 - 提前暴露Bean:如果是需要提前暴露bean,則添加一個暴露沒有注入屬性的bean的方法到緩存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
。此處是爲了解決循環依賴,可查看:spring中怎麼解決循環依賴。 - 注入屬性:
populateBean
除了處理標籤中的property,還利用BeanPostProcessor去處理【2】中收集的@Resource、@Autowired等,完成依賴注入。—CommonAnnotationBeanPostProcessor
以及AutowiredAnnotationBeanPostProcessor
- 初始化bean(完成注入後的操作):
initializeBean
,這裏的鉤子就比較多:
a. invokeAwareMethods:響應BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口。
b. applyBeanPostProcessorsBeforeInitialization:遍歷BeanPostProcess調用BeanPostProcessor#postProcessBeforeInitialization
c. invokeInitMethods:
-InitializeBean.afterPropertiesSet
:如果該bean有實現InitializeBean接口,則調用。
- invokeCustomInitMethod(initMethod):如果有<bean>
有配置init-method
則調用。
d. applyBeanPostProcessorsAfterInitialization:遍歷BeanPostProcess調用BeanPostProcessor#postProcessAfterInitialization
小結
1.a爲常用的Aware接口,b、d爲常用的BeanPostProcessor接口,c爲常用InitializingBean接口。
2.重點類BeanpostProcessor:CommonAnnotationBeanPostProcessor
、AutowiredAnnotationBeanPostProcessor
總結
createBean 過程總之就是獲得BeanDefinition的信息,通過反射創建實例,再注入依賴,然後initializeBean
完成特殊處理,最後放入緩存中。 在整個過程中,留下了許多鉤子,我們可以使用Aware接口,BeanPostProcessor去做特殊處理。
最後再放一張詳細的圖: