Spring IoC學(xué)習(xí)之ApplicationContext中refresh過(guò)程詳解
refresh()
該方法是 Spring Bean 加載的核心,它是 ClassPathXmlApplicationContext 的父類(lèi) AbstractApplicationContext 的一個(gè)方法 , 顧名思義,用于刷新整個(gè)Spring 上下文信息,定義了整個(gè) Spring 上下文加載的流程。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
//準(zhǔn)備刷新上下文 環(huán)境
this.prepareRefresh();
//初始化BeanFactory,并進(jìn)行XML文件讀取
/*
* ClassPathXMLApplicationContext包含著B(niǎo)eanFactory所提供的一切特征,在這一步驟中將會(huì)復(fù)用
* BeanFactory中的配置文件讀取解析及其他功能,這一步之后,ClassPathXmlApplicationContext
* 實(shí)際上就已經(jīng)包含了BeanFactory所提供的功能,也就是可以進(jìn)行Bean的提取等基礎(chǔ)操作了。
*/
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//對(duì)beanFactory進(jìn)行各種功能填充
this.prepareBeanFactory(beanFactory);
try {
//子類(lèi)覆蓋方法做額外處理
this.postProcessBeanFactory(beanFactory);
//激活各種beanFactory處理器
this.invokeBeanFactoryPostProcessors(beanFactory);
//注冊(cè)攔截Bean創(chuàng)建的Bean處理器,這里只是注冊(cè),真正的調(diào)用實(shí)在getBean時(shí)候
this.registerBeanPostProcessors(beanFactory);
//為上下文初始化Message源,即不同語(yǔ)言的消息體,國(guó)際化處理
this.initMessageSource();
//初始化應(yīng)用消息廣播器,并放入“applicationEventMulticaster”bean中
this.initApplicationEventMulticaster();
//留給子類(lèi)來(lái)初始化其它的Bean
this.onRefresh();
//在所有注冊(cè)的bean中查找Listener bean,注冊(cè)到消息廣播器中
this.registerListeners();
//初始化剩下的單實(shí)例(非惰性的)
this.finishBeanFactoryInitialization(beanFactory);
//完成刷新過(guò)程,通知生命周期處理器lifecycleProcessor刷新過(guò)程,同時(shí)發(fā)出ContextRefreshEvent通知?jiǎng)e人
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
每個(gè)子方法的功能之后一點(diǎn)一點(diǎn)再分析,首先 refresh()方法有幾點(diǎn)是值得我們學(xué)習(xí)的:
- 方法是加鎖的,這么做的原因是避免多線程同時(shí)刷新 Spring 上下文;
- 盡管加鎖可以看到是針對(duì)整個(gè)方法體的,但是沒(méi)有在方法前加 synchronized 關(guān)鍵字,而使用了對(duì)象鎖 startUpShutdownMonitor,這樣做有兩個(gè)好處:
(1)refresh()方法和 close()方法都使用了 startUpShutdownMonitor 對(duì)象鎖加鎖,這就保證了在調(diào)用 refresh()方法的時(shí)候無(wú)法調(diào)用 close()方法,反之依然,這樣就避免了沖突。
(2)使用對(duì)象鎖可以減小同步的范圍,只對(duì)不能并發(fā)的代碼塊進(jìn)行加鎖,提高了整體代碼運(yùn)行的速率。 - 在 refresh()方法中整合了很多個(gè)子方法,使得整個(gè)方法流程清晰易懂。這樣一來(lái),方便代碼的可讀性和可維護(hù)性。
3.1 prepareRefresh方法
//設(shè)置啟動(dòng)時(shí)間,是否激活標(biāo)識(shí)位,初始化屬性源(property source)配置
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (this.logger.isDebugEnabled()) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Refreshing " + this);
} else {
this.logger.debug("Refreshing " + this.getDisplayName());
}
}
// 在上下文環(huán)境中初始化任何占位符屬性源。(空的方法,留給子類(lèi)覆蓋)
this.initPropertySources();
//驗(yàn)證所有的必需的屬性是否可解析,若無(wú)則不能解析并拋出異常
this.getEnvironment().validateRequiredProperties();
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
} else {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
this.earlyApplicationEvents = new LinkedHashSet();
}
prepareRefresh 的內(nèi)容如上,該方法主要進(jìn)行環(huán)境的準(zhǔn)備,包括 Context 的啟動(dòng)時(shí)間,活動(dòng)狀態(tài),然后設(shè)置 context 中的配置數(shù)據(jù)源,使用默認(rèn)的 StandardEnvironment 對(duì)象,該對(duì)象添加了 System.env()屬性和 System.properties()屬性 。 initPropertySources 方法用于初始化 context 中 environment 的屬性源。在 AbstractApplicationContext 中為空實(shí)現(xiàn)。其他子類(lèi)的實(shí)現(xiàn)如下:

在子類(lèi) GenericWebApplicationContext 和 AbstractRefreshableWebApplicationContext 的實(shí)現(xiàn)大致一致,都是:
protected void initPropertySources() {
ConfigurableEnvironment env = this.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(this.servletContext, this.servletConfig);
}
}
通過(guò)在 getEnvironment 方法中,重寫(xiě) createEnvironment 方法 。
protected ConfigurableEnvironment createEnvironment() {
return new StandardServletEnvironment();
}
將 AbstractApplicationContext 類(lèi)中默認(rèn)的 StandardEnvironment 替換為StandardServletEnvironment, StandardServletEnvironment 的關(guān)系圖為:

因而會(huì)執(zhí)行 StandardServletEnvironment 類(lèi)的 initPropertySources 方法,為 context 添加 ServletContext 和 ServletConfig 對(duì)應(yīng)的配置屬性源。
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}
接著是分析 this.getEnvironment().validateRequiredProperties()方法,在上述我們已經(jīng)提到 getEnvironment()返回的不再是默認(rèn)的 StandardEnvironment 而是替換為了 StandardServletEnvironment,在此基礎(chǔ)上查找 validateRequiredProperties()的實(shí)現(xiàn)方法,最終定位到了 AbstractEnvironment 類(lèi)中:
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
this.propertyResolver.validateRequiredProperties();
}
this.propertyResolver 指的是 PropertySourcesPropertyResolver 對(duì)象,最終具體實(shí)現(xiàn)定位在 AbstractPropertyResolver 類(lèi)中:
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
Iterator var2 = this.requiredProperties.iterator();
while(var2.hasNext()) {
String key = (String)var2.next();
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) {
throw ex;
}
}

3.2 obtainFreshBeanFactory
該方法的實(shí)現(xiàn)如下,通過(guò) refreshBeanFactory 重置 AbstractApplicationContext 持有的 BeanFactory,然后通過(guò) getBeanFactory 獲取該對(duì)象并返回。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
return this.getBeanFactory();
}
AbstractApplicationContext 中 refreshBeanFacoty 方法和 getBeanFactory 方法都是抽象方法, 具體實(shí)現(xiàn)在 AbstractRefreshableApplicationContext 中。
protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
//銷(xiāo)毀已經(jīng)存在的單例bean
this.destroyBeans();
//銷(xiāo)毀已有的BeanFactory
this.closeBeanFactory();
}
try {
//創(chuàng)建一個(gè)新的beanFactory,類(lèi)型為DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
//設(shè)置序列化id,為實(shí)例對(duì)象內(nèi)存中的十六進(jìn)制標(biāo)識(shí)
beanFactory.setSerializationId(this.getId());
//定制beanFactory,設(shè)置相關(guān)屬性,包括是否允許覆蓋同名稱的不同定義的對(duì)象以及循環(huán)依賴以及設(shè)置
this.customizeBeanFactory(beanFactory);
//加載BeanDefiniton
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
loadBeanDefinitions 在 AbstractRefreshableApplicationContext 中是個(gè)抽象方法,具體實(shí)現(xiàn)是在 AbstractXmlApplicationContext 中:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//為當(dāng)前工廠創(chuàng)建xml解析器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//配置當(dāng)前環(huán)境
beanDefinitionReader.setEnvironment(this.getEnvironment());
//配置資源解析器
beanDefinitionReader.setResourceLoader(this);
//配置schemas或者dtd的資源解析器,EntityResolver維護(hù)了url->schemalocation的路徑
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//子類(lèi)提供自定義的reader的初始化方法
this.initBeanDefinitionReader(beanDefinitionReader);
//加載bean定義
this.loadBeanDefinitions(beanDefinitionReader);
}
在 loadBeanDefinitions 方法中傳入了 DefaultListableBeanFactory 對(duì)象,并且初始化了 XmlBeanDefinitionReader 對(duì)象,接著就是初始化 bean 工廠的一些環(huán)境、類(lèi)加載器等。 繼續(xù)進(jìn)入到 loadBeanDefinitions(beanDefinitionReader)方法體中,代碼如下:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
這里的 configResources 和 configLocations 對(duì)應(yīng)兩種構(gòu)造函數(shù),其中 configLocations 是構(gòu)造函數(shù)A使用的。關(guān)于 loadBeanDefinitions 方法涉及的內(nèi)容比較多,我們挑一些重要的來(lái)看。以下是 AbstractBeanDefinitionReader 類(lèi)中的 loadBeanDefinitions 方法。
上述方法主要做兩件事:
- 調(diào)用資源加載器獲取資源 resourceLoader.getResource(location) 。
- 真正執(zhí)行加載功能的是子類(lèi) XmlBeanDefinitionReader的loadBeanDefinitions方法 。
其中 getResources 方法是在 PathMatchingResourcePatternResolver 類(lèi)實(shí)現(xiàn)的。
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
if (locationPattern.startsWith("classpath*:")) {
return this.getPathMatcher().isPattern(locationPattern.substring("classpath*:".length())) ? this.findPathMatchingResources(locationPattern) : this.findAllClassPathResources(locationPattern.substring("classpath*:".length()));
} else {
int prefixEnd = locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 : locationPattern.indexOf(58) + 1;
return this.getPathMatcher().isPattern(locationPattern.substring(prefixEnd)) ? this.findPathMatchingResources(locationPattern) : new Resource[]{this.getResourceLoader().getResource(locationPattern)};
}
}
count = this.loadBeanDefinitions(resources);中的 loadBeanDefinitions 方法具體實(shí)現(xiàn)在 XmlBeanDefinitionReader 類(lèi)中。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isTraceEnabled()) {
this.logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
//將資源文件轉(zhuǎn)換為類(lèi)型為InputStream的I/O流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//從InputStream中得到xML的解析源
InputSource inputSource = new InputSource(inputStream);
//編碼如果不為null, 則設(shè)置inputSource的編碼
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if (((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
getInputStream 方法用來(lái)加載 XML 文件,具體實(shí)現(xiàn)在 ClassPathResource 類(lèi)中,
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
} else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
} else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(this.getDescription() + " cannot be opened because it does not exist");
} else {
return is;
}
}
doLoadBeanDefinitions 用來(lái)注冊(cè) bean。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
//轉(zhuǎn)化為Document 對(duì)象
Document doc = this.doLoadDocument(inputSource, resource);
//啟動(dòng)對(duì)Bean定義解析的詳細(xì)過(guò)程,會(huì)用到Spring Bean的配置規(guī)則
int count = this.registerBeanDefinitions(doc, resource);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
} catch (BeanDefinitionStoreException var5) {
throw var5;
.....
}
后續(xù)關(guān)聯(lián)的代碼在此就不做介紹,后期我們?cè)賹W(xué)習(xí)。
因?yàn)樵?XmlBeanDefinitionReader 中已經(jīng)將之前初始化的 DefaultListableBeanFactory 注冊(cè)進(jìn)去了,所以 XmlBeanDefinitionReader 所讀取的 BeanDefinitionHolder 都會(huì)注冊(cè)到 DefinitionListableBeanFactory 中,也就是經(jīng)過(guò)這個(gè)步驟,DefaultListableBeanFactory 的變量 beanFactory 已經(jīng)包含了所有解析好的配置。
至此通過(guò)加載 XML 文件, 將xml文件解析為對(duì)應(yīng)的 BeanDefinition ,完成了 Bean 定義的加載和注冊(cè)。

3.3 prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//設(shè)置beanFactory的classLoader為當(dāng)前context的classloader
beanFactory.setBeanClassLoader(this.getClassLoader());
//設(shè)置beanFactory的表達(dá)式語(yǔ)言處理器,Spring3增加了表達(dá)式語(yǔ)言的支持,
//默認(rèn)可以使用#{bean.xxx}的形式來(lái)調(diào)用相關(guān)屬性值
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//設(shè)置PropertyEditorRegistrar,通過(guò)PropertyEditor將xml解析出來(lái)的bean屬性(字符串)和相應(yīng)的java類(lèi)型做轉(zhuǎn)換
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
/**
添加后置處理器ApplicationContextAwareProcessor,在Bean初始化后自動(dòng)執(zhí)行各Aware接口的set方法,包 括ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、 ApplicationContextAware、EnvironmentAware
**/
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
//預(yù)先設(shè)置用于自動(dòng)依賴注入的接口對(duì)象
//包括BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
//在 bean 實(shí)例化后,添加ApplicationListenerDetector,可以理解成:注冊(cè)事件監(jiān)聽(tīng)器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
//如果存在loadTimeWeaver這個(gè)Bean,則增加對(duì)應(yīng)的后置處理器
if (beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
//添加默認(rèn)的系統(tǒng)環(huán)境bean
if (!beanFactory.containsLocalBean("environment")) {
beanFactory.registerSingleton("environment", this.getEnvironment());
}
if (!beanFactory.containsLocalBean("systemProperties")) {
beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean("systemEnvironment")) {
beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
}
}
其中反復(fù)出現(xiàn)了 addBeanPostProcessor 方法,該方法具體實(shí)現(xiàn)在 AbstractBeanFactory 類(lèi)中。
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
this.beanPostProcessors.remove(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
this.beanPostProcessors.add(beanPostProcessor);
}
詳細(xì)分析下代碼發(fā)現(xiàn)上面函數(shù)主要是在以下方法進(jìn)行了擴(kuò)展:
- 對(duì)SPEL語(yǔ)言的支持
- 增加對(duì)屬性編輯器的支持
- 增加對(duì)一些內(nèi)置類(lèi)的支持,如EnvironmentAware、MessageSourceAware的注入
- 設(shè)置了依賴功能可忽略的接口
- 注冊(cè)一些固定依賴的屬性
- 如果存在loadTimeWeaver這個(gè)Bean,則增加對(duì)應(yīng)的后置處理器
- 將相關(guān)環(huán)境變量及屬性以單例模式注冊(cè)
3.4 postProcessBeanFactory
所有 Bean 的定義已經(jīng)加載完成,但是沒(méi)有實(shí)例化,這一步可以修改 bean 定義或者增加自定義的 bean。該方法主要是承接上文中的 prepareBeanFactory 方法,增加一些后置處理器。具體實(shí)現(xiàn)在 AbstractRefreshableWebApplicationContext 類(lèi)中。
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//增加ServletContextAwareProcessor后置處理器
//用于處理ServletContextAware接口和ServletConfigAware接口中相關(guān)對(duì)象的自動(dòng)注入
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
//注冊(cè)web環(huán)境,包括request、session、golableSession、application
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
//注冊(cè)servletContext、contextParamters、contextAttributes、servletConfig單例bean
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
3.5 invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
在執(zhí)行 invokeBeanFactoryPostProcessors 方法前查看 beanFactory,對(duì)比執(zhí)行后發(fā)現(xiàn)此處有所不同。

在 Spring 容器中找出實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 Bean 并執(zhí)行。Spring 容器會(huì)委托給 PostProcessorRegistrationDelegate 的 invokeBeanFactoryPostProcessors 方法執(zhí)行。
通過(guò)調(diào)試發(fā)現(xiàn),ClassPathXmlApplicationContext 類(lèi)中的 beanFactoryPostProcessors 屬性為空,所以執(zhí)行 invokeBeanFactoryPostProcessors 方法時(shí)也是如此。

那么我們執(zhí)行該方法有什么用呢?那么還有什么地方可能存在實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 Bean,帶著疑問(wèn),我們?nèi)ゲ榭?PostProcessorRegistrationDelegate 中的 invokeBeanFactoryPostProcessors 方法。
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet();
ArrayList regularPostProcessors;
ArrayList registryProcessors;
int var9;
....
}
這一段代碼特別長(zhǎng),一開(kāi)始看起來(lái)肯定覺(jué)得很難,不知道從哪入手,這里我介紹一下我的學(xué)習(xí)方法,對(duì)測(cè)試代碼進(jìn)行 debug 調(diào)試,進(jìn)入該方法后一步一步往下執(zhí)行,遇到外部引用的方法記下來(lái),待會(huì)調(diào)試完畢找到該方法,然后再打斷點(diǎn)進(jìn)行調(diào)試。反復(fù)來(lái)幾遍,大概就能理解這個(gè)方法做了什么事情。
首先該方法的參數(shù) beanFactory 實(shí)際類(lèi)型為 DefaultListableBeanFactory,beanFactoryPostProcessors 參數(shù)內(nèi)容為空。調(diào)試過(guò)程中發(fā)現(xiàn)比較重要的方法是 getBeanNamesForType 方法,該方法有三個(gè)參數(shù)值,具體實(shí)現(xiàn)在 DefaultListableBeanFactory 類(lèi)中。
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (this.isConfigurationFrozen() && type != null && allowEagerInit) {
Map<Class<?>, String[]> cache = includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType;
String[] resolvedBeanNames = (String[])cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
} else {
resolvedBeanNames = this.doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, this.getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
} else {
return this.doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
}
invokeBeanFactoryPostProcessors 方法代碼在調(diào)用 getBeanNamesForType 方法時(shí)根據(jù)第一個(gè)參數(shù)類(lèi)型的不同分為兩類(lèi): BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 。其中 BeanDefinitionRegistryPostProcessor 繼承自 BeanFactoryPostProcessor。執(zhí)行的時(shí)候,先找出所有的 BeanDefinitionRegistryPostProcessor 執(zhí)行再找出所有 BeanFactoryPostProcessor 執(zhí)行。因?yàn)?BeanDefinitionRegistryPostProcessor 繼承自 BeanFactoryPostProcessor,所以執(zhí)行后者時(shí)會(huì)過(guò)濾掉前者的內(nèi)容。
在調(diào)試中發(fā)現(xiàn)只有當(dāng)參數(shù)為 BeanFactoryPostProcessor.class 時(shí),才會(huì)獲取到有效的內(nèi)容。 getBeanNamesForType 方法中的關(guān)鍵部分是 doGetBeanNamesForType 方法,該方法主要是將 XML 文件中定義的實(shí)現(xiàn)了BeanFactoryPostProcessor的 bean 的 id 取出來(lái),以及將 XML 文件中定義的 bean 加載到 beanFactory 中。


等待 getBeanNamesForType 返回這些內(nèi)容后,接著就會(huì)實(shí)例化并初始化實(shí)現(xiàn) BeanFactoryPostProcessor 接口的類(lèi)并執(zhí)行。這里比較關(guān)鍵的代碼是 invokeBeanFactoryPostProcessors 和 PropertyResourceConfigurer 類(lèi)中的 postProcessBeanFactory 方法。
private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
Iterator var2 = postProcessors.iterator();
while(var2.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
postProcessor.postProcessBeanFactory(beanFactory);
}
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
Properties mergedProps = this.mergeProperties();
this.convertProperties(mergedProps);
this.processProperties(beanFactory, mergedProps);
} catch (IOException var3) {
throw new BeanInitializationException("Could not load properties", var3);
}
}
當(dāng) PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法執(zhí)行完畢后,查看 beanFactory 的狀態(tài)。

3.6 registerBeanPostProcessors
從 Spring 容器中找出的 BeanPostProcessor 接口的 Bean,并添加到 BeanFactory 內(nèi)部維護(hù)的 List 屬性中,以便后續(xù) Bean 被實(shí)例化的時(shí)候調(diào)用這個(gè) BeanPostProcessor進(jìn)行回調(diào)處理。該方法委托給了 PostProcessorRegistrationDelegate 類(lèi)的 registerBeanPostProcessors 方法執(zhí)行。
同 invokeBeanFactoryPostProcessors 類(lèi)似, 先從容器中獲取所有類(lèi)型為 BeanPostProcessor.class 的 Bean 的 name 數(shù)組,然后通過(guò) BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); 獲取Bean的實(shí)例,最后通過(guò) registerBeanPostProcessors(beanFactory, orderedPostProcessors);將獲取到的 BeanPostProcessor 實(shí)例添加到容器的屬性中。在實(shí)際過(guò)程中會(huì)根據(jù) AbstractBeanFactory 類(lèi)中的 isTypeMatch 方法對(duì) bean 實(shí)例進(jìn)行篩選,具體順序?yàn)椋?/p>
- 將實(shí)現(xiàn) PriorityOrdered 接口的 BeanPostProcessor 列表添加到 beanFactory 中
- 將實(shí)現(xiàn) Ordered 接口的 BeanPostProcessor 列表添加到 beanFactory 中
- 將剩余的 BeanPostProcessor 列表添加到 beanFactory 中
- 將實(shí)現(xiàn) MergedBeanDefinitionPostProcessor 接口的 BeanPostProcessor 列表添加到 beanFactory 中
另外在 PostProcessorRegistrationDelegate 類(lèi)中有個(gè)內(nèi)部類(lèi) BeanPostProcessorChecker,它實(shí)現(xiàn)了 BeanPostProcessor 接口,所以最后會(huì)有一個(gè) BeanPostProcessorChecker 類(lèi)添加到 beanFactory 中。
最終該方法用來(lái)實(shí)例化并初始化實(shí)現(xiàn) BeanPostProcessor 接口的類(lèi),但不執(zhí)行。
3.7 initMessageSource
在 Spring 容器中初始化一些國(guó)際化相關(guān)的屬性 。
3.8 initApplicationEventMulticaster
初始化 ApplicationEventMulticaste (事件廣播器)是在方法 initApplicationEventMulticaster()中實(shí)現(xiàn)的,進(jìn)入到方法體,如下:
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
// 1、默認(rèn)使用內(nèi)置的事件廣播器,如果有的話.
// 我們可以在配置文件中配置Spring事件廣播器或者自定義事件廣播器
// 例如: <bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster"></bean>
if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
} else {
// 2、否則,新建一個(gè)事件廣播器,SimpleApplicationEventMulticaster是spring的默認(rèn)事件廣播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
通過(guò)源碼可以看出該方法實(shí)現(xiàn)邏輯與 initMessageSource 基本相同,其步驟如下:查找是否有 name 為 applicationEventMulticaster 的 bean,如果有則放到容器里,如果沒(méi)有,初始化一個(gè)系統(tǒng)默認(rèn)的 SimpleApplicationEventMulticaster 對(duì)象放入容器。
3.9 onRefresh
模塊方法,可用于 refresh 動(dòng)作的擴(kuò)展,默認(rèn)為空實(shí)現(xiàn)。在 SpringBoot 中主要用于啟動(dòng)內(nèi)嵌的 Web 服務(wù)器。
3.10 registerListeners
注冊(cè)監(jiān)聽(tīng)器,找出系統(tǒng)中的 ApplicationListener 對(duì)象,注冊(cè)到時(shí)間廣播器中。如果有需要提前進(jìn)行廣播的事件,則執(zhí)行廣播。
protected void registerListeners() {
// 首先,注冊(cè)指定的靜態(tài)事件監(jiān)聽(tīng)器,在spring boot中有應(yīng)用
Iterator var1 = this.getApplicationListeners().iterator();
while(var1.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var1.next();
this.getApplicationEventMulticaster().addApplicationListener(listener);
}
// 其次,注冊(cè)普通的事件監(jiān)聽(tīng)器
String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
String[] var7 = listenerBeanNames;
int var3 = listenerBeanNames.length;
for(int var4 = 0; var4 < var3; ++var4) {
String listenerBeanName = var7[var4];
this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 如果有早期事件的話,在這里進(jìn)行事件廣播
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
Iterator var9 = earlyEventsToProcess.iterator();
while(var9.hasNext()) {
ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
3.11 finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 判斷有無(wú)ConversionService(bean屬性類(lèi)型轉(zhuǎn)換服務(wù)接口),并初始化
if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
}
// 如果beanFactory中不包含EmbeddedValueResolver,則向其中添加一個(gè)EmbeddedValueResolver
if (!beanFactory.hasEmbeddedValueResolver()) {// EmbeddedValueResolver-->解析bean中的占位符和表達(dá)式
beanFactory.addEmbeddedValueResolver((strVal) -> {
return this.getEnvironment().resolvePlaceholders(strVal);
});
}
// 初始化LoadTimeWeaverAware類(lèi)型的bean
// LoadTimeWeaverAware-->加載Spring Bean時(shí)織入第三方模塊,如AspectJ
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
String[] var3 = weaverAwareNames;
int var4 = weaverAwareNames.length;
for(int var5 = 0; var5 < var4; ++var5) {
String weaverAwareName = var3[var5];
this.getBean(weaverAwareName);
}
// 釋放臨時(shí)類(lèi)加載器
beanFactory.setTempClassLoader((ClassLoader)null);
// 凍結(jié)緩存的BeanDefinition元數(shù)據(jù)
beanFactory.freezeConfiguration();
// 初始化其他的非延遲加載的單例bean
beanFactory.preInstantiateSingletons();
}
實(shí)例化 BeanFactory 中已經(jīng)被注冊(cè)但是未實(shí)例化的所有實(shí)例(懶加載的不需要實(shí)例化),主要操作是 BeanFactory 的 preInstantiateSingletons 方法。該方法分為兩部分:
- 遍歷已經(jīng)解析出來(lái)的所有 beanDefinitionNames,如果該 BeanDefinition 不是抽象類(lèi)、是單例且沒(méi)有設(shè)置懶加載,則進(jìn)行實(shí)例化和初始化。
- 遍歷解析出來(lái)的 beanDefinitionNames,如果獲得的單例是 SmartInitializingSingleton 的實(shí)現(xiàn)類(lèi),則會(huì)執(zhí)行 afterSingletonsInstantiated 方法。注意該方法調(diào)用只會(huì)發(fā)生在啟動(dòng)階段,后續(xù)懶加載對(duì)象再初始化的時(shí)候,不會(huì)再進(jìn)行回調(diào)。
3.12 finishRefresh
完成刷新過(guò)程,通知生命周期處理器 lifecycleProcessor 刷新過(guò)程,同時(shí)發(fā)出 ContextRefreshEvent 通知。
總結(jié)
到此這篇關(guān)于Spring IoC學(xué)習(xí)之ApplicationContext中refresh過(guò)程詳解的文章就介紹到這了,更多相關(guān)Spring ApplicationContext中refresh過(guò)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java令牌Token登錄與退出的實(shí)現(xiàn)
這篇文章主要介紹了Java令牌Token登錄與退出的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
解決cmd運(yùn)行java程序“找不到文件”提示的方案
在本篇文章里小編給大家分享的是關(guān)于解決cmd運(yùn)行java程序“找不到文件”提示的方案,有需要的朋友們可以參考下。2020-02-02
Java中JSONObject和Map<String,?Object>的轉(zhuǎn)換方法
平時(shí)對(duì)接口時(shí),經(jīng)常遇到j(luò)son字符串和map對(duì)象之間的交互,這篇文章主要給大家介紹了關(guān)于Java中JSONObject和Map<String,?Object>的轉(zhuǎn)換方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07
Spring?Boot項(xiàng)目傳參校驗(yàn)的最佳實(shí)踐指南
有參數(shù)傳遞的地方都少不了參數(shù)校驗(yàn),在web開(kāi)發(fā)中前端的參數(shù)校驗(yàn)是為了用戶體驗(yàn),后端的參數(shù)校驗(yàn)是為了安全,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot項(xiàng)目傳參校驗(yàn)的最佳實(shí)踐,需要的朋友可以參考下2022-04-04
Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用詳解
項(xiàng)目日志記錄是項(xiàng)目開(kāi)發(fā)、運(yùn)營(yíng)必不可少的內(nèi)容,有了它可以對(duì)系統(tǒng)有整體的把控,出現(xiàn)任何問(wèn)題都有蹤跡可尋。下面這篇文章主要給大家介紹了關(guān)于Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用的相關(guān)資料,需要的朋友可以參考下。2017-12-12
Spring?Boot指標(biāo)監(jiān)控及日志管理示例詳解
Spring Boot Actuator可以幫助程序員監(jiān)控和管理SpringBoot應(yīng)用,比如健康檢查、內(nèi)存使用情況統(tǒng)計(jì)、線程使用情況統(tǒng)計(jì)等,這篇文章主要介紹了Spring?Boot指標(biāo)監(jiān)控及日志管理,需要的朋友可以參考下2023-11-11

