Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解
refresh()
該方法是 Spring Bean 加載的核心,它是 ClassPathXmlApplicationContext 的父類 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包含著BeanFactory所提供的一切特征,在這一步驟中將會(huì)復(fù)用 * BeanFactory中的配置文件讀取解析及其他功能,這一步之后,ClassPathXmlApplicationContext * 實(shí)際上就已經(jīng)包含了BeanFactory所提供的功能,也就是可以進(jìn)行Bean的提取等基礎(chǔ)操作了。 */ ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); //對(duì)beanFactory進(jìn)行各種功能填充 this.prepareBeanFactory(beanFactory); try { //子類覆蓋方法做額外處理 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(); //留給子類來初始化其它的Bean this.onRefresh(); //在所有注冊(cè)的bean中查找Listener bean,注冊(cè)到消息廣播器中 this.registerListeners(); //初始化剩下的單實(shí)例(非惰性的) this.finishBeanFactoryInitialization(beanFactory); //完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程,同時(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è)方法體的,但是沒有在方法前加 synchronized 關(guān)鍵字,而使用了對(duì)象鎖 startUpShutdownMonitor,這樣做有兩個(gè)好處:
(1)refresh()方法和 close()方法都使用了 startUpShutdownMonitor 對(duì)象鎖加鎖,這就保證了在調(diào)用 refresh()方法的時(shí)候無法調(diào)用 close()方法,反之依然,這樣就避免了沖突。
(2)使用對(duì)象鎖可以減小同步的范圍,只對(duì)不能并發(fā)的代碼塊進(jìn)行加鎖,提高了整體代碼運(yùn)行的速率。 - 在 refresh()方法中整合了很多個(gè)子方法,使得整個(gè)方法流程清晰易懂。這樣一來,方便代碼的可讀性和可維護(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)境中初始化任何占位符屬性源。(空的方法,留給子類覆蓋) this.initPropertySources(); //驗(yàn)證所有的必需的屬性是否可解析,若無則不能解析并拋出異常 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)。其他子類的實(shí)現(xiàn)如下:
在子類 GenericWebApplicationContext 和 AbstractRefreshableWebApplicationContext 的實(shí)現(xiàn)大致一致,都是:
protected void initPropertySources() { ConfigurableEnvironment env = this.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment)env).initPropertySources(this.servletContext, this.servletConfig); } }
通過在 getEnvironment 方法中,重寫 createEnvironment 方法 。
protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); }
將 AbstractApplicationContext 類中默認(rèn)的 StandardEnvironment 替換為StandardServletEnvironment, StandardServletEnvironment 的關(guān)系圖為:
因而會(huì)執(zhí)行 StandardServletEnvironment 類的 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 類中:
public void validateRequiredProperties() throws MissingRequiredPropertiesException { this.propertyResolver.validateRequiredProperties(); }
this.propertyResolver 指的是 PropertySourcesPropertyResolver 對(duì)象,最終具體實(shí)現(xiàn)定位在 AbstractPropertyResolver 類中:
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)如下,通過 refreshBeanFactory 重置 AbstractApplicationContext 持有的 BeanFactory,然后通過 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()) { //銷毀已經(jīng)存在的單例bean this.destroyBeans(); //銷毀已有的BeanFactory this.closeBeanFactory(); } try { //創(chuàng)建一個(gè)新的beanFactory,類型為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)); //子類提供自定義的reader的初始化方法 this.initBeanDefinitionReader(beanDefinitionReader); //加載bean定義 this.loadBeanDefinitions(beanDefinitionReader); }
在 loadBeanDefinitions 方法中傳入了 DefaultListableBeanFactory 對(duì)象,并且初始化了 XmlBeanDefinitionReader 對(duì)象,接著就是初始化 bean 工廠的一些環(huán)境、類加載器等。 繼續(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)容比較多,我們挑一些重要的來看。以下是 AbstractBeanDefinitionReader 類中的 loadBeanDefinitions 方法。
上述方法主要做兩件事:
- 調(diào)用資源加載器獲取資源 resourceLoader.getResource(location) 。
- 真正執(zhí)行加載功能的是子類 XmlBeanDefinitionReader的loadBeanDefinitions方法 。
其中 getResources 方法是在 PathMatchingResourcePatternResolver 類實(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 類中。
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)換為類型為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 方法用來加載 XML 文件,具體實(shí)現(xiàn)在 ClassPathResource 類中,
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 用來注冊(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ì)過程,會(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)過這個(gè)步驟,DefaultListableBeanFactory 的變量 beanFactory 已經(jīng)包含了所有解析好的配置。
至此通過加載 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}的形式來調(diào)用相關(guān)屬性值 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //設(shè)置PropertyEditorRegistrar,通過PropertyEditor將xml解析出來的bean屬性(字符串)和相應(yīng)的java類型做轉(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)聽器 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 類中。
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)置類的支持,如EnvironmentAware、MessageSourceAware的注入
- 設(shè)置了依賴功能可忽略的接口
- 注冊(cè)一些固定依賴的屬性
- 如果存在loadTimeWeaver這個(gè)Bean,則增加對(duì)應(yīng)的后置處理器
- 將相關(guān)環(huán)境變量及屬性以單例模式注冊(cè)
3.4 postProcessBeanFactory
所有 Bean 的定義已經(jīng)加載完成,但是沒有實(shí)例化,這一步可以修改 bean 定義或者增加自定義的 bean。該方法主要是承接上文中的 prepareBeanFactory 方法,增加一些后置處理器。具體實(shí)現(xiàn)在 AbstractRefreshableWebApplicationContext 類中。
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í)行。
通過調(diào)試發(fā)現(xiàn),ClassPathXmlApplicationContext 類中的 beanFactoryPostProcessors 屬性為空,所以執(zhí)行 invokeBeanFactoryPostProcessors 方法時(shí)也是如此。
那么我們執(zhí)行該方法有什么用呢?那么還有什么地方可能存在實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 Bean,帶著疑問,我們?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),一開始看起來肯定覺得很難,不知道從哪入手,這里我介紹一下我的學(xué)習(xí)方法,對(duì)測(cè)試代碼進(jìn)行 debug 調(diào)試,進(jìn)入該方法后一步一步往下執(zhí)行,遇到外部引用的方法記下來,待會(huì)調(diào)試完畢找到該方法,然后再打斷點(diǎn)進(jìn)行調(diào)試。反復(fù)來幾遍,大概就能理解這個(gè)方法做了什么事情。
首先該方法的參數(shù) beanFactory 實(shí)際類型為 DefaultListableBeanFactory,beanFactoryPostProcessors 參數(shù)內(nèi)容為空。調(diào)試過程中發(fā)現(xiàn)比較重要的方法是 getBeanNamesForType 方法,該方法有三個(gè)參數(shù)值,具體實(shí)現(xiàn)在 DefaultListableBeanFactory 類中。
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ù)類型的不同分為兩類: BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 。其中 BeanDefinitionRegistryPostProcessor 繼承自 BeanFactoryPostProcessor。執(zhí)行的時(shí)候,先找出所有的 BeanDefinitionRegistryPostProcessor 執(zhí)行再找出所有 BeanFactoryPostProcessor 執(zhí)行。因?yàn)?BeanDefinitionRegistryPostProcessor 繼承自 BeanFactoryPostProcessor,所以執(zhí)行后者時(shí)會(huì)過濾掉前者的內(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 取出來,以及將 XML 文件中定義的 bean 加載到 beanFactory 中。
等待 getBeanNamesForType 返回這些內(nèi)容后,接著就會(huì)實(shí)例化并初始化實(shí)現(xiàn) BeanFactoryPostProcessor 接口的類并執(zhí)行。這里比較關(guān)鍵的代碼是 invokeBeanFactoryPostProcessors 和 PropertyResourceConfigurer 類中的 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 類的 registerBeanPostProcessors 方法執(zhí)行。
同 invokeBeanFactoryPostProcessors 類似, 先從容器中獲取所有類型為 BeanPostProcessor.class 的 Bean 的 name 數(shù)組,然后通過 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); 獲取Bean的實(shí)例,最后通過 registerBeanPostProcessors(beanFactory, orderedPostProcessors);將獲取到的 BeanPostProcessor 實(shí)例添加到容器的屬性中。在實(shí)際過程中會(huì)根據(jù) AbstractBeanFactory 類中的 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 類中有個(gè)內(nèi)部類 BeanPostProcessorChecker,它實(shí)現(xiàn)了 BeanPostProcessor 接口,所以最后會(huì)有一個(gè) BeanPostProcessorChecker 類添加到 beanFactory 中。
最終該方法用來實(shí)例化并初始化實(shí)現(xiàn) BeanPostProcessor 接口的類,但不執(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() + "]"); } } }
通過源碼可以看出該方法實(shí)現(xiàn)邏輯與 initMessageSource 基本相同,其步驟如下:查找是否有 name 為 applicationEventMulticaster 的 bean,如果有則放到容器里,如果沒有,初始化一個(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)中的 ApplicationListener 對(duì)象,注冊(cè)到時(shí)間廣播器中。如果有需要提前進(jìn)行廣播的事件,則執(zhí)行廣播。
protected void registerListeners() { // 首先,注冊(cè)指定的靜態(tài)事件監(jiān)聽器,在spring boot中有應(yīng)用 Iterator var1 = this.getApplicationListeners().iterator(); while(var1.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var1.next(); this.getApplicationEventMulticaster().addApplicationListener(listener); } // 其次,注冊(cè)普通的事件監(jiān)聽器 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) { // 判斷有無ConversionService(bean屬性類型轉(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類型的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í)類加載器 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)解析出來的所有 beanDefinitionNames,如果該 BeanDefinition 不是抽象類、是單例且沒有設(shè)置懶加載,則進(jìn)行實(shí)例化和初始化。
- 遍歷解析出來的 beanDefinitionNames,如果獲得的單例是 SmartInitializingSingleton 的實(shí)現(xiàn)類,則會(huì)執(zhí)行 afterSingletonsInstantiated 方法。注意該方法調(diào)用只會(huì)發(fā)生在啟動(dòng)階段,后續(xù)懶加載對(duì)象再初始化的時(shí)候,不會(huì)再進(jìn)行回調(diào)。
3.12 finishRefresh
完成刷新過程,通知生命周期處理器 lifecycleProcessor 刷新過程,同時(shí)發(fā)出 ContextRefreshEvent 通知。
總結(jié)
到此這篇關(guān)于Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解的文章就介紹到這了,更多相關(guān)Spring ApplicationContext中refresh過程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java令牌Token登錄與退出的實(shí)現(xiàn)
這篇文章主要介紹了Java令牌Token登錄與退出的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05解決cmd運(yùn)行java程序“找不到文件”提示的方案
在本篇文章里小編給大家分享的是關(guān)于解決cmd運(yùn)行java程序“找不到文件”提示的方案,有需要的朋友們可以參考下。2020-02-02Java中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)換方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07Spring?Boot項(xiàng)目傳參校驗(yàn)的最佳實(shí)踐指南
有參數(shù)傳遞的地方都少不了參數(shù)校驗(yàn),在web開發(fā)中前端的參數(shù)校驗(yàn)是為了用戶體驗(yàn),后端的參數(shù)校驗(yàn)是為了安全,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot項(xiàng)目傳參校驗(yàn)的最佳實(shí)踐,需要的朋友可以參考下2022-04-04Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用詳解
項(xiàng)目日志記錄是項(xiàng)目開發(fā)、運(yùn)營(yíng)必不可少的內(nèi)容,有了它可以對(duì)系統(tǒng)有整體的把控,出現(xiàn)任何問題都有蹤跡可尋。下面這篇文章主要給大家介紹了關(guān)于Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用的相關(guān)資料,需要的朋友可以參考下。2017-12-12Spring?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