av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁技術(shù)文章
文章詳情頁

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

瀏覽:3日期:2023-08-17 14:02:48

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(); //對beanFactory進(jìn)行各種功能填充 this.prepareBeanFactory(beanFactory);​ try { //子類覆蓋方法做額外處理 this.postProcessBeanFactory(beanFactory); //激活各種beanFactory處理器 this.invokeBeanFactoryPostProcessors(beanFactory); //注冊攔截Bean創(chuàng)建的Bean處理器,這里只是注冊,真正的調(diào)用實(shí)在getBean時(shí)候 this.registerBeanPostProcessors(beanFactory); //為上下文初始化Message源,即不同語言的消息體,國際化處理 this.initMessageSource(); //初始化應(yīng)用消息廣播器,并放入“applicationEventMulticaster”bean中 this.initApplicationEventMulticaster(); //留給子類來初始化其它的Bean this.onRefresh(); //在所有注冊的bean中查找Listener bean,注冊到消息廣播器中 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 上下文; 盡管加鎖可以看到是針對整個(gè)方法體的,但是沒有在方法前加 synchronized 關(guān)鍵字,而使用了對象鎖 startUpShutdownMonitor,這樣做有兩個(gè)好處: (1)refresh()方法和 close()方法都使用了 startUpShutdownMonitor 對象鎖加鎖,這就保證了在調(diào)用 refresh()方法的時(shí)候無法調(diào)用 close()方法,反之依然,這樣就避免了沖突。 (2)使用對象鎖可以減小同步的范圍,只對不能并發(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 對象,該對象添加了 System.env()屬性和 System.properties()屬性 。 initPropertySources 方法用于初始化 context 中 environment 的屬性源。在 AbstractApplicationContext 中為空實(shí)現(xiàn)。其他子類的實(shí)現(xiàn)如下:

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

在子類 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)系圖為:

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

因而會(huì)執(zhí)行 StandardServletEnvironment 類的 initPropertySources 方法,為 context 添加 ServletContext 和 ServletConfig 對應(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 對象,最終具體實(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; }}

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

3.2 obtainFreshBeanFactory

該方法的實(shí)現(xiàn)如下,通過 refreshBeanFactory 重置 AbstractApplicationContext 持有的 BeanFactory,然后通過 getBeanFactory 獲取該對象并返回。

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í)例對象內(nèi)存中的十六進(jìn)制標(biāo)識(shí) beanFactory.setSerializationId(this.getId()); //定制beanFactory,設(shè)置相關(guān)屬性,包括是否允許覆蓋同名稱的不同定義的對象以及循環(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 對象,并且初始化了 XmlBeanDefinitionReader 對象,接著就是初始化 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 對應(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 用來注冊 bean。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //轉(zhuǎn)化為Document 對象 Document doc = this.doLoadDocument(inputSource, resource); //啟動(dòng)對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)的代碼在此就不做介紹,后期我們再學(xué)習(xí)。

因?yàn)樵?XmlBeanDefinitionReader 中已經(jīng)將之前初始化的 DefaultListableBeanFactory 注冊進(jìn)去了,所以 XmlBeanDefinitionReader 所讀取的 BeanDefinitionHolder 都會(huì)注冊到 DefinitionListableBeanFactory 中,也就是經(jīng)過這個(gè)步驟,DefaultListableBeanFactory 的變量 beanFactory 已經(jīng)包含了所有解析好的配置。

至此通過加載 XML 文件, 將xml文件解析為對應(yīng)的 BeanDefinition ,完成了 Bean 定義的加載和注冊。

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

3.3 prepareBeanFactory

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //設(shè)置beanFactory的classLoader為當(dāng)前context的classloader beanFactory.setBeanClassLoader(this.getClassLoader()); //設(shè)置beanFactory的表達(dá)式語言處理器,Spring3增加了表達(dá)式語言的支持, //默認(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)依賴注入的接口對象 //包括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,可以理解成:注冊事件監(jiān)聽器 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); //如果存在loadTimeWeaver這個(gè)Bean,則增加對應(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ò)展:

對SPEL語言的支持 增加對屬性編輯器的支持 增加對一些內(nèi)置類的支持,如EnvironmentAware、MessageSourceAware的注入 設(shè)置了依賴功能可忽略的接口 注冊一些固定依賴的屬性 如果存在loadTimeWeaver這個(gè)Bean,則增加對應(yīng)的后置處理器 將相關(guān)環(huán)境變量及屬性以單例模式注冊

3.4 postProcessBeanFactory

所有 Bean 的定義已經(jīng)加載完成,但是沒有實(shí)例化,這一步可以修改 bean 定義或者增加自定義的 bean。該方法主要是承接上文中的 prepareBeanFactory 方法,增加一些后置處理器。具體實(shí)現(xiàn)在 AbstractRefreshableWebApplicationContext 類中。

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //增加ServletContextAwareProcessor后置處理器 //用于處理ServletContextAware接口和ServletConfigAware接口中相關(guān)對象的自動(dòng)注入 beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); beanFactory.ignoreDependencyInterface(ServletContextAware.class); beanFactory.ignoreDependencyInterface(ServletConfigAware.class); //注冊web環(huán)境,包括request、session、golableSession、application WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); //注冊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,對比執(zhí)行后發(fā)現(xiàn)此處有所不同。

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

在 Spring 容器中找出實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 Bean 并執(zhí)行。Spring 容器會(huì)委托給 PostProcessorRegistrationDelegate 的 invokeBeanFactoryPostProcessors 方法執(zhí)行。

通過調(diào)試發(fā)現(xiàn),ClassPathXmlApplicationContext 類中的 beanFactoryPostProcessors 屬性為空,所以執(zhí)行 invokeBeanFactoryPostProcessors 方法時(shí)也是如此。

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

那么我們執(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; ....}

這一段代碼特別長,一開始看起來肯定覺得很難,不知道從哪入手,這里我介紹一下我的學(xué)習(xí)方法,對測試代碼進(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 中。

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

等待 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)。

Spring IoC學(xué)習(xí)之ApplicationContext中refresh過程詳解

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 方法對 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ā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 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 對象放入容器。

3.9 onRefresh

模塊方法,可用于 refresh 動(dòng)作的擴(kuò)展,默認(rèn)為空實(shí)現(xiàn)。在 SpringBoot 中主要用于啟動(dòng)內(nèi)嵌的 Web 服務(wù)器。

3.10 registerListeners

注冊監(jiān)聽器,找出系統(tǒng)中的 ApplicationListener 對象,注冊到時(shí)間廣播器中。如果有需要提前進(jìn)行廣播的事件,則執(zhí)行廣播。

protected void registerListeners() { // 首先,注冊指定的靜態(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); } // 其次,注冊普通的事件監(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)被注冊但是未實(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ù)懶加載對象再初始化的時(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)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 成人精品在线视频 | 在线免费观看黄色av | 伊人热久久 | 99久久久久 | 特级黄色毛片 | 国产精品69毛片高清亚洲 | 欧美男人亚洲天堂 | 欧美午夜精品理论片a级按摩 | 亚洲精品一二区 | 国产99在线 | 欧美 | 插插宗合网 | 成人在线视频一区 | 青青久久 | 精品中文视频 | 欧美精品一区二区三区四区五区 | 成人三级av | www97影院| 久久国产精99精产国高潮 | 你懂的国产 | re久久 | 日韩欧美在线观看 | 欧美一级在线视频 | 一区二区三区四区在线视频 | 久久久久久99 | 国产91网址 | 中文字幕在线不卡播放 | 不卡一区| 在线婷婷 | 国产一二区免费视频 | 国产精品久久久久久久久久99 | 97人人超碰 | 国产精品久久久久久久久久久久 | 日韩电影一区 | 国产精品久久久久久久久久免费 | 国产精品国产三级国产aⅴ无密码 | 亚洲成人高清 | 亚洲成人一二三 | 99国产精品视频免费观看一公开 | 中文字幕亚洲一区二区va在线 | 亚洲色片网站 | 操到爽 |