前兩篇我們講了BeanDefinition加載以及BeanFactory后置處理器沥阱,主要分析了registry和invokeBeanFactoryPostProcessors這兩個方法蝌衔。今天我們來分析另外兩個重要的方法。registerBeanPostProcessors和finishBeanFactoryInitialization遗锣。這些方法都在AnnotationConfigApplicationContext的refresh方法中生真。
注冊Bean 后置處理器
registerBeanPostProcessors方法負(fù)責(zé)初始化實現(xiàn)了BeanPostProcessor接口的Bean铣除,并將其注冊到BeanFactory中闹丐。
后置處理器BeanPostProcessor定義了兩個方法postProcessBeforeInitialization和postProcessAfterInitialization。Spring會添加所有的BeanPostProcessor到BeanFactory的beanPostProcessors列表中赚导。
BeanPostProcessor可以理解成輔助類茬缩,在所有其它類型的Bean(應(yīng)用Bean)初始化過程中,Spring會分別在它們初始化前后調(diào)用BeanPostProcessor實例的postProcessBeforeInitialization和postProcessAfterInitialization吼旧。
前面講的BeanFactoryPostProcessor凰锡,和BeanPostProcessor是一樣的。在BeanFactory創(chuàng)建之后圈暗,Spring會調(diào)用所有BeanFactoryPostProcessor實例的postProcessBeanFactory方法掂为,這樣為用戶提供了在BeanFactory創(chuàng)建之后,對Bean進(jìn)行擴展的機會员串。
現(xiàn)在來看registerBeanPostProcessors源碼:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 調(diào)用PostProcessorRegistrationDelegate的registerBeanPostProcessors方法
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
看PostProcessorRegistrationDelegate的registerBeanPostProcessors的源代碼:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 獲取所有的postProcessor names
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
// 放到nonOrderedPostProcessorNames列表中勇哗,這里省略了其它代碼,都是處理優(yōu)先級的寸齐。BesnPostProcessor也可以設(shè)置優(yōu)先級的欲诺,優(yōu)先級高的會先被調(diào)用抄谐。
nonOrderedPostProcessorNames.add(ppName);
}
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
// 實例化BeanPostProcessor實例
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
}
// 注冊BestProcessor
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
}
看registerBeanPostProcessors源碼:
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
// 把所有的BeanPostProcessor添加到beanFactory中
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
beanFactory是一個DefaultListableBeanFactory對象,我們來看其代碼扰法,很簡單蛹含,幾乎就是一行代碼:
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// 將beanPostProcessor添加到beanPostProcessors列表中
this.beanPostProcessors.add(beanPostProcessor);
}
在創(chuàng)建所有的應(yīng)用bean調(diào)用initializeBean方法時,會輪詢beanPostProcessors中的對象塞颁,并在Bean實例化前后分別調(diào)用postProcessBeforeInitialization和postProcessAfterInitialization方法挣惰。
好的,注冊BeanPostProcessor講完了殴边,注冊過程比較簡單锤岸,主要是講了一下它在Spring Bean初始化過程中的作用板乙。我們接下來看最最重要的一個方法finishBeanFactoryInitialization。
初始化Bean對象
refresh方法中我們最后要講的一個方法是finishBeanFactoryInitialization蛋铆,它負(fù)責(zé)根據(jù)BeanDefinition創(chuàng)建Bean對象,并執(zhí)行一些與Bean生命周期相關(guān)的回調(diào)函數(shù)放接。我們直接看源碼:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 省略其它處理代碼刺啦,直接調(diào)用beanFactory的preInstantiateSingletons.
beanFactory.preInstantiateSingletons();
}
始終記住beanFactory是DefaultListableBeanFactory對象,所以看它的preInstantiateSingletons源碼纠脾。
// 這里要注意玛瘸,只初始化所有singletons的Bean,關(guān)于prototype類型的bean,是每次調(diào)用getBean都會創(chuàng)建的苟蹈,不會在容器啟動的時候初始化糊渊。
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
// 這里省略了FactoryBean對象處理邏輯,如果是isEglarBean慧脱,也會調(diào)用getBean方法渺绒。所以簡單理解為菱鸥,不管是哪種sigleton bean宗兼,都會調(diào)用getBean方法
getBean(beanName);
}
// 省略SmartInitializingSingleton的處理,有興趣的可以去了解一下這個類的作用...
}
public Object getBean(String name) throws BeansException {
// getBean其實調(diào)用了doGetBean方法采缚。
return doGetBean(name, null, null, false);
}
來看doGetBean的代碼,為了減少文章內(nèi)容扳抽,只貼了核心代碼:
final String beanName = transformedBeanName(name);
Object bean;
// 取單利Bean篡帕,這里簡單介紹一下DefaultListableBeanFactory的另一種集成關(guān)系,它繼承了DefaultSingletonBeanRegistry類镰烧。這個類允許單利管理拢军,簡單講就是其中定義了一個HashMap<String,Object>怔鳖,維護(hù)了bean名字和Bean對象的關(guān)系度陆,并且保證每一個Bean名字只創(chuàng)建一個Bean對象。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 如果緩存(上面說的HashMap)中存在bean蹬蚁,則取這個bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// BeanFactory是可以繼承的,如果當(dāng)前BeanFactory中找不到Bean定義叽粹,就從父BeanFactory中去找。
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
// 省略了參數(shù)處理的過程。直接從父BeanFactory去找每强。
return (T) parentBeanFactory.getBean(nameToLookup);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 這里先處理Bean依賴,如果當(dāng)前Bean依賴其它Bean辨绊,則先注冊并實例化依賴的Bean.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 先注冊依賴Bean
registerDependentBean(dep, beanName);
// 再實例化依賴Bean
getBean(dep);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
// 創(chuàng)建單利Bean
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// Prototyp類型的Bean,是每次都會創(chuàng)建的冻晤。
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 處理其它類型的Bean,如一些擴展的類型Session鼻弧,Request等等,代碼省略了..
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 類型轉(zhuǎn)換的代碼也省略了...
return (T) bean;
來看一下createBean做了哪些事情锦茁。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
// 其它代碼都省略了攘轩,就是調(diào)用了doCreateBean方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
來看doCreateBean的代碼:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 創(chuàng)建BeanWrapper.
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
// 調(diào)用createBeanInstance創(chuàng)建Bean實例,這個方法我們不再仔細(xì)往下閱讀了码俩,大致的思路是根據(jù)RootBeanDefinition找到其類型classType撑刺,然后再獲取其構(gòu)造函數(shù),然后根據(jù)構(gòu)造函數(shù)使用反射動態(tài)創(chuàng)建出一個bean實例握玛,再對這個實例進(jìn)行一下包裝,返回BeanWrapper對象甫菠。當(dāng)需要對bean增強的時候挠铲,創(chuàng)建bean也可能使用CGLib動態(tài)創(chuàng)建,我們這里只講最簡單的情況寂诱。
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Object exposedObject = bean;
try {
// 根據(jù)BeanDefinition對bean屬性進(jìn)行賦值拂苹。
populateBean(beanName, mbd, instanceWrapper);
// 初始化Bean,在這里執(zhí)行Bean生命周期的回調(diào)函數(shù),如設(shè)置beanName痰洒,調(diào)用postBestProcessor等瓢棒。
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
}
return exposedObject;
}
上面的兩個重要方法分別是createBeanInstance和initializeBean。其中createBeanInstance所做的事情大致是根據(jù)RootBeanDefinition找到其類型classType丘喻,然后再獲取其構(gòu)造函數(shù)脯宿,然后根據(jù)構(gòu)造函數(shù)使用反射動態(tài)創(chuàng)建出一個bean實例,再對這個實例進(jìn)行一下包裝泉粉,返回BeanWrapper對象连霉。因為這個類的業(yè)務(wù)很簡單,大部分代碼都是在處理一些與反射有關(guān)的東西嗡靡,所以我們不再進(jìn)行分析了跺撼。我們把重點放在initializeBean這個方法上。
來看initializeBean的代碼:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 執(zhí)行*Aware接口的方法讨彼,Spring提供了大量的*Aware接口歉井,用來給Bean設(shè)置值,如可以向Bean中注入ApplicationContext哈误,ClassLoader等哩至。
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 如果Bean實現(xiàn)了BeanPostProcessor接口躏嚎,則執(zhí)行postProcessBeforeInitialization方法。
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 執(zhí)行bean初始化相關(guān)方法憨募。如果bean實現(xiàn)了InitializingBean接口紧索,則會調(diào)用其afterPropertiesSet方法。如果bean指定了用戶自定義的init-method方法菜谣,自定義方法也會被執(zhí)行珠漂。
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 如果Bean實現(xiàn)了BeanPostProcessor接口,則執(zhí)行postProcessAfterInitialization方法尾膊。
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
上面代碼中相關(guān)接口方法的執(zhí)行都很直接媳危,就是判斷Bean對象是否實現(xiàn)了某個接口,如果實現(xiàn)了該接口冈敛,就調(diào)用接口定義的方法待笑。initializeBean是比較重要的方法,它涉及到了Bean的生命周期抓谴,是面試的衬乎澹考點。它也確實比較重要癌压,我們可以在Bean初始化期間做很多事情仰泻。
到目前為止,Bean初始化也講完了滩届,從finishBeanFactoryInitialization->getBean->createBean->initializeBean集侯。完成了bean的初始化并執(zhí)行Bean生命周期中相關(guān)的回調(diào)方法。
總結(jié)
今天講了注冊bean后置處理器以及bean的加載帜消。
Spring定義了BeanPostProcessor接口棠枉,所有實現(xiàn)了該接口的bean,都將被注冊到spring的后置處理器列表中泡挺。后置處理器相當(dāng)于是一些輔助類辈讶,所有的應(yīng)用bean在初始化之后,都會調(diào)用所有的后置處理器娄猫。這為用戶提供了在bean初始化前后荞估,修改或擴展bean的機會。
然后我們講了最重要的bean加載稚新。ApplicationContext會在啟動容器時勘伺,加載所有的非lazi-init的singleton bean。ApplicationContext實現(xiàn)了BeanDefinitionRegistry接口褂删,并在之前就已經(jīng)注冊了所有的BeanDefination飞醉,將其存儲在一個HashMap中。在加載bean時,從HashMap中讀取所有的BeanDefinition缅帘,并調(diào)用其getBean方法轴术。getBean本意是獲取bean,但是如果沒有钦无,則會創(chuàng)建并進(jìn)行初始化逗栽。
獲取bean時調(diào)用了doGetBean方法,首先會檢查當(dāng)前bean是否有定義失暂,如果沒有定義彼宠,則會去父BeanFactory中去查找。并且它也會檢查當(dāng)前bean是否依賴其它bean弟塞,如果依賴其它bean凭峡,則會先創(chuàng)建所依賴的bean。
創(chuàng)建bean是根據(jù)BeanDefinition中的classType决记,獲取其構(gòu)造函數(shù)摧冀,然后利用反射創(chuàng)建bean實例,然后調(diào)用populateBean方法進(jìn)行屬性設(shè)置系宫,最后調(diào)用initializeBean回調(diào)一些與bean生命周期有關(guān)的接口方法索昂。
至此,整個Spring的容器就啟動了扩借。