spring-boot源碼分析之BeanFactory · 壹
前言
今天原本是打算分析beanFactory的,但由于昨天我們有一部分內(nèi)容還沒有分享完,所以今天就先開個倒車,把昨天的內(nèi)容先講清楚了再說別的,因此今天的內(nèi)容主要就是對昨天分享內(nèi)容的的補(bǔ)充。
當(dāng)然,昨天我們分享的內(nèi)容beanDefinitionNames也算是BeanFactory的核心屬性,所以也不能說完全沒有關(guān)系:

而且從源碼中我們可以看出來,beanDefinitionNames、beanDefinitionMap這些屬性的初始化大小,這也算是在學(xué)習(xí)beanFactory的相關(guān)知識吧。
BeanFactory
beanDefinitionNames內(nèi)容補(bǔ)充
正式開始之前,我們先把昨天遺留的問題解決了。昨天,我們分享了一張beanDefinitionNames初始化的時序圖,但是由于有一些內(nèi)容沒有梳理清楚,所以這里先做個補(bǔ)充。

調(diào)用過程各方法作用
SpringApplication這里就不做過多說明了,我們在前面最開始的時候就已經(jīng)分析過這個類的run方法,當(dāng)時也已經(jīng)介紹過這個類的這些方法,他們的主要作用就是為了初始化容器,在SpringApplication的最后一個refresh方法中,最后會調(diào)用AbstractApplicationContext自身的refresh方法,這里的AbstractApplicationContext是ApplicationContext的抽象實(shí)現(xiàn),它實(shí)現(xiàn)了ConfigurableApplicationContext接口(ConfigurableApplicationContext繼承了ApplicationContext),我們的AnnotationConfigReactiveWebServerApplicationContext(默認(rèn)容器)就是繼承自它,不過并不是直接繼承,它的父類繼承了AbstractApplicationContext,關(guān)于容器這塊的繼承關(guān)系,我們改天抽個時間,專門分析下。
大部分繼承了AbstractApplicationContext的容器都沒有重寫refresh方法,就算重寫了這個方法,其內(nèi)部也是調(diào)用了父類的refresh方法:

我們看下refresh的實(shí)現(xiàn)源碼:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
refresh方法內(nèi)部,調(diào)用了很多其他方法,其中prepareRefresh的作用是為我們下面的刷新操作做準(zhǔn)備,其內(nèi)部主要是對配置的一些初始化操作:

obtainFreshBeanFactory方法的作用是刷新beanFactory,主要是對beanFactory進(jìn)行一些初始化操作,如果beanFactory已經(jīng)存在,會將已有的beanFactory銷毀,然后重新創(chuàng)建,最后將beanFactory返回:

prepareBeanFactory方法的作用是對BeanFactory進(jìn)行一些賦值和設(shè)置,為容器初始化操作做準(zhǔn)備:

postProcessBeanFactory方法就是我們昨天提到的會進(jìn)行包掃描的那個方法,但由于basePackages和annotatedClasses都是空,所以其中的scan方法并不會被執(zhí)行。這個方法實(shí)際的作用是,后置處理BeanFactory

invokeBeanFactoryPostProcessors方法的作用是,實(shí)例化并調(diào)用所有注冊的BeanFactory的后置處理器。我們昨天說的beanDefinitionNames和beanDefinitionMap就是通過這個方法最終完成初始化的:

registerBeanPostProcessors方法和它名字一樣,它的作用就是注冊bean的后置處理器:

initMessageSource方法是進(jìn)行消息源初始化的,主要是對web應(yīng)用消息國際化提供支持的:

initApplicationEventMulticaster,這個方法是初始化spring boot應(yīng)用時間廣播的,如果不指定的話,默認(rèn)情況下為我們指定的是SimpleApplicationEventMulticaster:

onRefresh,這個方法是提供給子類初始化其他特殊bean對象的,默認(rèn)實(shí)現(xiàn)為空,子類可根據(jù)需要重寫:

registerListeners方法是用來注冊事件監(jiān)聽器的:

finishBeanFactoryInitialization,完成beanFactory初始化,同時在方法內(nèi)部會實(shí)例化剩余的單例類(不包括懶加載部分):

finishRefresh,完成刷新,主要進(jìn)行一些清理、刷新、事件推送等操作:

總結(jié)
經(jīng)過今天的補(bǔ)充之后,我相信各位小伙伴一定也對spring boot的啟動和初始化過程有了更深刻的認(rèn)識,因?yàn)槲揖褪沁@樣的感受。相比于昨天分享完內(nèi)容的感受,今天我感覺整體來說要更好。一方面感覺spring boot啟動和初始化的流程更清晰了,而且由于最近這幾天一直在看spring boot的源碼,看的多了感覺就沒有那么難了,畢竟書讀百遍其意自現(xiàn),代碼也是大同小異;另一方面在梳理分析的過程中,讓我也能夠清晰地看到下一步要分享的內(nèi)容,明確后面的前進(jìn)方向,這也算是意外的收獲吧。
