refresh()
該方法是 Spring Bean 加載的核心,它是 ClassPathXmlApplicationContext 的父類 AbstractApplicationContext 的一個方法 , 顧名思義,用于刷新整個Spring 上下文信息,定義了整個 Spring 上下文加載的流程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public void refresh() throws BeansException, IllegalStateException { synchronized ( this .startupShutdownMonitor) { //準備刷新上下文 環境 this .prepareRefresh(); //初始化BeanFactory,并進行XML文件讀取 /* * ClassPathXMLApplicationContext包含著BeanFactory所提供的一切特征,在這一步驟中將會復用 * BeanFactory中的配置文件讀取解析及其他功能,這一步之后,ClassPathXmlApplicationContext * 實際上就已經包含了BeanFactory所提供的功能,也就是可以進行Bean的提取等基礎操作了。 */ ConfigurableListableBeanFactory beanFactory = this .obtainFreshBeanFactory(); //對beanFactory進行各種功能填充 this .prepareBeanFactory(beanFactory); ? try { //子類覆蓋方法做額外處理 this .postProcessBeanFactory(beanFactory); //激活各種beanFactory處理器 this .invokeBeanFactoryPostProcessors(beanFactory); //注冊攔截Bean創建的Bean處理器,這里只是注冊,真正的調用實在getBean時候 this .registerBeanPostProcessors(beanFactory); //為上下文初始化Message源,即不同語言的消息體,國際化處理 this .initMessageSource(); //初始化應用消息廣播器,并放入“applicationEventMulticaster”bean中 this .initApplicationEventMulticaster(); //留給子類來初始化其它的Bean this .onRefresh(); //在所有注冊的bean中查找Listener bean,注冊到消息廣播器中 this .registerListeners(); //初始化剩下的單實例(非惰性的) this .finishBeanFactoryInitialization(beanFactory); //完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人 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(); } ? } } |
每個子方法的功能之后一點一點再分析,首先 refresh()方法有幾點是值得我們學習的:
- 方法是加鎖的,這么做的原因是避免多線程同時刷新 Spring 上下文;
-
盡管加鎖可以看到是針對整個方法體的,但是沒有在方法前加 synchronized 關鍵字,而使用了對象鎖 startUpShutdownMonitor,這樣做有兩個好處:
(1)refresh()方法和 close()方法都使用了 startUpShutdownMonitor 對象鎖加鎖,這就保證了在調用 refresh()方法的時候無法調用 close()方法,反之依然,這樣就避免了沖突。
(2)使用對象鎖可以減小同步的范圍,只對不能并發的代碼塊進行加鎖,提高了整體代碼運行的速率。 - 在 refresh()方法中整合了很多個子方法,使得整個方法流程清晰易懂。這樣一來,方便代碼的可讀性和可維護性。
3.1 prepareRefresh方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
//設置啟動時間,是否激活標識位,初始化屬性源(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()); } } ? // 在上下文環境中初始化任何占位符屬性源。(空的方法,留給子類覆蓋) this .initPropertySources(); //驗證所有的必需的屬性是否可解析,若無則不能解析并拋出異常 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 的內容如上,該方法主要進行環境的準備,包括 Context 的啟動時間,活動狀態,然后設置 context 中的配置數據源,使用默認的 StandardEnvironment 對象,該對象添加了 System.env()屬性和 System.properties()屬性 。 initPropertySources 方法用于初始化 context 中 environment 的屬性源。在 AbstractApplicationContext 中為空實現。其他子類的實現如下:
在子類 GenericWebApplicationContext 和 AbstractRefreshableWebApplicationContext 的實現大致一致,都是:
1
2
3
4
5
6
7
|
protected void initPropertySources() { ConfigurableEnvironment env = this .getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment)env).initPropertySources( this .servletContext, this .servletConfig); } ? } |
通過在 getEnvironment 方法中,重寫 createEnvironment 方法 。
1
2
3
|
protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); } |
將 AbstractApplicationContext 類中默認的 StandardEnvironment 替換為StandardServletEnvironment, StandardServletEnvironment 的關系圖為:
因而會執行 StandardServletEnvironment 類的 initPropertySources 方法,為 context 添加 ServletContext 和 ServletConfig 對應的配置屬性源。
1
2
3
|
public void initPropertySources( @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) { WebApplicationContextUtils.initServletPropertySources( this .getPropertySources(), servletContext, servletConfig); } |
接著是分析 this.getEnvironment().validateRequiredProperties()方法,在上述我們已經提到 getEnvironment()返回的不再是默認的 StandardEnvironment 而是替換為了 StandardServletEnvironment,在此基礎上查找 validateRequiredProperties()的實現方法,最終定位到了 AbstractEnvironment 類中:
1
2
3
|
public void validateRequiredProperties() throws MissingRequiredPropertiesException { this .propertyResolver.validateRequiredProperties(); } |
this.propertyResolver 指的是 PropertySourcesPropertyResolver 對象,最終具體實現定位在 AbstractPropertyResolver 類中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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
該方法的實現如下,通過 refreshBeanFactory 重置 AbstractApplicationContext 持有的 BeanFactory,然后通過 getBeanFactory 獲取該對象并返回。
1
2
3
4
|
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { this .refreshBeanFactory(); return this .getBeanFactory(); } |
AbstractApplicationContext 中 refreshBeanFacoty 方法和 getBeanFactory 方法都是抽象方法, 具體實現在 AbstractRefreshableApplicationContext 中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
protected final void refreshBeanFactory() throws BeansException { if ( this .hasBeanFactory()) { //銷毀已經存在的單例bean this .destroyBeans(); //銷毀已有的BeanFactory this .closeBeanFactory(); } ? try { //創建一個新的beanFactory,類型為DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = this .createBeanFactory(); //設置序列化id,為實例對象內存中的十六進制標識 beanFactory.setSerializationId( this .getId()); //定制beanFactory,設置相關屬性,包括是否允許覆蓋同名稱的不同定義的對象以及循環依賴以及設置 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 中是個抽象方法,具體實現是在 AbstractXmlApplicationContext 中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //為當前工廠創建xml解析器 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); //配置當前環境 beanDefinitionReader.setEnvironment( this .getEnvironment()); //配置資源解析器 beanDefinitionReader.setResourceLoader( this ); //配置schemas或者dtd的資源解析器,EntityResolver維護了url->schemalocation的路徑 beanDefinitionReader.setEntityResolver( new ResourceEntityResolver( this )); //子類提供自定義的reader的初始化方法 this .initBeanDefinitionReader(beanDefinitionReader); //加載bean定義 this .loadBeanDefinitions(beanDefinitionReader); } |
在 loadBeanDefinitions 方法中傳入了 DefaultListableBeanFactory 對象,并且初始化了 XmlBeanDefinitionReader 對象,接著就是初始化 bean 工廠的一些環境、類加載器等。 繼續進入到 loadBeanDefinitions(beanDefinitionReader)方法體中,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
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 對應兩種構造函數,其中 configLocations 是構造函數A使用的。關于 loadBeanDefinitions 方法涉及的內容比較多,我們挑一些重要的來看。以下是 AbstractBeanDefinitionReader 類中的 loadBeanDefinitions 方法。
1
|
|
上述方法主要做兩件事:
- 調用資源加載器獲取資源 resourceLoader.getResource(location) 。
- 真正執行加載功能的是子類 XmlBeanDefinitionReader的loadBeanDefinitions方法 。
其中 getResources 方法是在 PathMatchingResourcePatternResolver 類實現的。
1
2
3
4
5
6
7
8
9
|
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 方法具體實現在 XmlBeanDefinitionReader 類中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
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 { //將資源文件轉換為類型為InputStream的I/O流 InputStream inputStream = encodedResource.getResource().getInputStream(); ? try { //從InputStream中得到xML的解析源 InputSource inputSource = new InputSource(inputStream); //編碼如果不為null, 則設置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 文件,具體實現在 ClassPathResource 類中,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //轉化為Document 對象 Document doc = this .doLoadDocument(inputSource, resource); //啟動對Bean定義解析的詳細過程,會用到Spring Bean的配置規則 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; ..... } |
后續關聯的代碼在此就不做介紹,后期我們再學習。
因為在 XmlBeanDefinitionReader 中已經將之前初始化的 DefaultListableBeanFactory 注冊進去了,所以 XmlBeanDefinitionReader 所讀取的 BeanDefinitionHolder 都會注冊到 DefinitionListableBeanFactory 中,也就是經過這個步驟,DefaultListableBeanFactory 的變量 beanFactory 已經包含了所有解析好的配置。
至此通過加載 XML 文件, 將xml文件解析為對應的 BeanDefinition ,完成了 Bean 定義的加載和注冊。
3.3 prepareBeanFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //設置beanFactory的classLoader為當前context的classloader beanFactory.setBeanClassLoader( this .getClassLoader()); //設置beanFactory的表達式語言處理器,Spring3增加了表達式語言的支持, //默認可以使用#{bean.xxx}的形式來調用相關屬性值 beanFactory.setBeanExpressionResolver( new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //設置PropertyEditorRegistrar,通過PropertyEditor將xml解析出來的bean屬性(字符串)和相應的java類型做轉換 beanFactory.addPropertyEditorRegistrar( new ResourceEditorRegistrar( this , this .getEnvironment())); /** 添加后置處理器ApplicationContextAwareProcessor,在Bean初始化后自動執行各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 ); //預先設置用于自動依賴注入的接口對象 //包括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 實例化后,添加ApplicationListenerDetector,可以理解成:注冊事件監聽器 beanFactory.addBeanPostProcessor( new ApplicationListenerDetector( this )); //如果存在loadTimeWeaver這個Bean,則增加對應的后置處理器 if (beanFactory.containsBean( "loadTimeWeaver" )) { beanFactory.addBeanPostProcessor( new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader( new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } //添加默認的系統環境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()); } } |
其中反復出現了 addBeanPostProcessor 方法,該方法具體實現在 AbstractBeanFactory 類中。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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); } |
詳細分析下代碼發現上面函數主要是在以下方法進行了擴展:
- 對SPEL語言的支持
- 增加對屬性編輯器的支持
- 增加對一些內置類的支持,如EnvironmentAware、MessageSourceAware的注入
- 設置了依賴功能可忽略的接口
- 注冊一些固定依賴的屬性
- 如果存在loadTimeWeaver這個Bean,則增加對應的后置處理器
- 將相關環境變量及屬性以單例模式注冊
3.4 postProcessBeanFactory
所有 Bean 的定義已經加載完成,但是沒有實例化,這一步可以修改 bean 定義或者增加自定義的 bean。該方法主要是承接上文中的 prepareBeanFactory 方法,增加一些后置處理器。具體實現在 AbstractRefreshableWebApplicationContext 類中。
1
2
3
4
5
6
7
8
9
10
11
|
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //增加ServletContextAwareProcessor后置處理器 //用于處理ServletContextAware接口和ServletConfigAware接口中相關對象的自動注入 beanFactory.addBeanPostProcessor( new ServletContextAwareProcessor( this .servletContext, this .servletConfig)); beanFactory.ignoreDependencyInterface(ServletContextAware. class ); beanFactory.ignoreDependencyInterface(ServletConfigAware. class ); //注冊web環境,包括request、session、golableSession、application WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this .servletContext); //注冊servletContext、contextParamters、contextAttributes、servletConfig單例bean WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this .servletContext, this .servletConfig); } |
3.5 invokeBeanFactoryPostProcessors
1
2
3
4
5
6
7
8
|
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())); } } |
在執行 invokeBeanFactoryPostProcessors 方法前查看 beanFactory,對比執行后發現此處有所不同。
在 Spring 容器中找出實現了 BeanFactoryPostProcessor 接口的 Bean 并執行。Spring 容器會委托給 PostProcessorRegistrationDelegate 的 invokeBeanFactoryPostProcessors 方法執行。
通過調試發現,ClassPathXmlApplicationContext 類中的 beanFactoryPostProcessors 屬性為空,所以執行 invokeBeanFactoryPostProcessors 方法時也是如此。
那么我們執行該方法有什么用呢?那么還有什么地方可能存在實現了 BeanFactoryPostProcessor 接口的 Bean,帶著疑問,我們去查看 PostProcessorRegistrationDelegate 中的 invokeBeanFactoryPostProcessors 方法。
1
2
3
4
5
6
7
|
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { Set<String> processedBeans = new HashSet(); ArrayList regularPostProcessors; ArrayList registryProcessors; int var9; .... } |
這一段代碼特別長,一開始看起來肯定覺得很難,不知道從哪入手,這里我介紹一下我的學習方法,對測試代碼進行 debug 調試,進入該方法后一步一步往下執行,遇到外部引用的方法記下來,待會調試完畢找到該方法,然后再打斷點進行調試。反復來幾遍,大概就能理解這個方法做了什么事情。
首先該方法的參數 beanFactory 實際類型為 DefaultListableBeanFactory,beanFactoryPostProcessors 參數內容為空。調試過程中發現比較重要的方法是 getBeanNamesForType 方法,該方法有三個參數值,具體實現在 DefaultListableBeanFactory 類中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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 方法代碼在調用 getBeanNamesForType 方法時根據第一個參數類型的不同分為兩類: BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 。其中 BeanDefinitionRegistryPostProcessor 繼承自 BeanFactoryPostProcessor。執行的時候,先找出所有的 BeanDefinitionRegistryPostProcessor 執行再找出所有 BeanFactoryPostProcessor 執行。因為 BeanDefinitionRegistryPostProcessor 繼承自 BeanFactoryPostProcessor,所以執行后者時會過濾掉前者的內容。
在調試中發現只有當參數為 BeanFactoryPostProcessor.class 時,才會獲取到有效的內容。 getBeanNamesForType 方法中的關鍵部分是 doGetBeanNamesForType 方法,該方法主要是將 XML 文件中定義的實現了BeanFactoryPostProcessor的 bean 的 id 取出來,以及將 XML 文件中定義的 bean 加載到 beanFactory 中。
等待 getBeanNamesForType 返回這些內容后,接著就會實例化并初始化實現 BeanFactoryPostProcessor 接口的類并執行。這里比較關鍵的代碼是 invokeBeanFactoryPostProcessors 和 PropertyResourceConfigurer 類中的 postProcessBeanFactory 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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); } } |
當 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法執行完畢后,查看 beanFactory 的狀態。
3.6 registerBeanPostProcessors
從 Spring 容器中找出的 BeanPostProcessor 接口的 Bean,并添加到 BeanFactory 內部維護的 List 屬性中,以便后續 Bean 被實例化的時候調用這個 BeanPostProcessor進行回調處理。該方法委托給了 PostProcessorRegistrationDelegate 類的 registerBeanPostProcessors 方法執行。
同 invokeBeanFactoryPostProcessors 類似, 先從容器中獲取所有類型為 BeanPostProcessor.class 的 Bean 的 name 數組,然后通過 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); 獲取Bean的實例,最后通過 registerBeanPostProcessors(beanFactory, orderedPostProcessors);將獲取到的 BeanPostProcessor 實例添加到容器的屬性中。在實際過程中會根據 AbstractBeanFactory 類中的 isTypeMatch 方法對 bean 實例進行篩選,具體順序為:
- 將實現 PriorityOrdered 接口的 BeanPostProcessor 列表添加到 beanFactory 中
- 將實現 Ordered 接口的 BeanPostProcessor 列表添加到 beanFactory 中
- 將剩余的 BeanPostProcessor 列表添加到 beanFactory 中
- 將實現 MergedBeanDefinitionPostProcessor 接口的 BeanPostProcessor 列表添加到 beanFactory 中
另外在 PostProcessorRegistrationDelegate 類中有個內部類 BeanPostProcessorChecker,它實現了 BeanPostProcessor 接口,所以最后會有一個 BeanPostProcessorChecker 類添加到 beanFactory 中。
最終該方法用來實例化并初始化實現 BeanPostProcessor 接口的類,但不執行。
3.7 initMessageSource
在 Spring 容器中初始化一些國際化相關的屬性 。
3.8 initApplicationEventMulticaster
初始化 ApplicationEventMulticaste (事件廣播器)是在方法 initApplicationEventMulticaster()中實現的,進入到方法體,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = this .getBeanFactory(); // 1、默認使用內置的事件廣播器,如果有的話. // 我們可以在配置文件中配置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、否則,新建一個事件廣播器,SimpleApplicationEventMulticaster是spring的默認事件廣播器 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() + "]" ); } } } |
通過源碼可以看出該方法實現邏輯與 initMessageSource 基本相同,其步驟如下:查找是否有 name 為 applicationEventMulticaster 的 bean,如果有則放到容器里,如果沒有,初始化一個系統默認的 SimpleApplicationEventMulticaster 對象放入容器。
3.9 onRefresh
模塊方法,可用于 refresh 動作的擴展,默認為空實現。在 SpringBoot 中主要用于啟動內嵌的 Web 服務器。
3.10 registerListeners
注冊監聽器,找出系統中的 ApplicationListener 對象,注冊到時間廣播器中。如果有需要提前進行廣播的事件,則執行廣播。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
protected void registerListeners() { // 首先,注冊指定的靜態事件監聽器,在spring boot中有應用 Iterator var1 = this .getApplicationListeners().iterator(); while (var1.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var1.next(); this .getApplicationEventMulticaster().addApplicationListener(listener); } // 其次,注冊普通的事件監聽器 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); } // 如果有早期事件的話,在這里進行事件廣播 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 判斷有無ConversionService(bean屬性類型轉換服務接口),并初始化 if (beanFactory.containsBean( "conversionService" ) && beanFactory.isTypeMatch( "conversionService" , ConversionService. class )) { beanFactory.setConversionService((ConversionService)beanFactory.getBean( "conversionService" , ConversionService. class )); } // 如果beanFactory中不包含EmbeddedValueResolver,則向其中添加一個EmbeddedValueResolver if (!beanFactory.hasEmbeddedValueResolver()) { // EmbeddedValueResolver-->解析bean中的占位符和表達式 beanFactory.addEmbeddedValueResolver((strVal) -> { return this .getEnvironment().resolvePlaceholders(strVal); }); } // 初始化LoadTimeWeaverAware類型的bean // LoadTimeWeaverAware-->加載Spring Bean時織入第三方模塊,如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); } // 釋放臨時類加載器 beanFactory.setTempClassLoader((ClassLoader) null ); // 凍結緩存的BeanDefinition元數據 beanFactory.freezeConfiguration(); // 初始化其他的非延遲加載的單例bean beanFactory.preInstantiateSingletons(); } |
實例化 BeanFactory 中已經被注冊但是未實例化的所有實例(懶加載的不需要實例化),主要操作是 BeanFactory 的 preInstantiateSingletons 方法。該方法分為兩部分:
- 遍歷已經解析出來的所有 beanDefinitionNames,如果該 BeanDefinition 不是抽象類、是單例且沒有設置懶加載,則進行實例化和初始化。
- 遍歷解析出來的 beanDefinitionNames,如果獲得的單例是 SmartInitializingSingleton 的實現類,則會執行 afterSingletonsInstantiated 方法。注意該方法調用只會發生在啟動階段,后續懶加載對象再初始化的時候,不會再進行回調。
3.12 finishRefresh
完成刷新過程,通知生命周期處理器 lifecycleProcessor 刷新過程,同時發出 ContextRefreshEvent 通知。
總結
到此這篇關于Spring IoC學習之ApplicationContext中refresh過程詳解的文章就介紹到這了,更多相關Spring ApplicationContext中refresh過程內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://zhuanlan.zhihu.com/p/107827442