1. 程式人生 > >死磕Spring之IoC篇 - Spring 應用上下文 ApplicationContext

死磕Spring之IoC篇 - Spring 應用上下文 ApplicationContext

> 該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 [Spring 原始碼分析 GitHub 地址](https://github.com/liu844869663/spring-framework) 進行閱讀 > > Spring 版本:5.1.14.RELEASE > > 開始閱讀這一系列文章之前,建議先檢視[**《深入瞭解 Spring IoC(面試題)》**](https://www.cnblogs.com/lifullmoon/p/14422101.html)這一篇文章 > > 該系列其他文章請檢視:[**《死磕 Spring 之 IoC 篇 - 文章導讀》**](https://www.cnblogs.com/lifullmoon/p/14436372.html) ## Spring 應用上下文 ApplicationContext 前面一系列文章都是圍繞 BeanFactory 進行分析的,BeanFactory 是 Spring 底層 IoC 容器的實現,完成了 IoC 容器的基本功能。在實際的應用場景中,BeanFactory 容器有點簡單,它並不適用於生產環境,我們通常會選擇 ApplicationContext。ApplicationContext 就是大名鼎鼎的 Spring 應用上下文,它不僅繼承了 BeanFactory 體系,還提供更加高階的功能,更加適用於我們的正式應用環境。如以下幾個功能: - 繼承 MessageSource,提供國際化的標準訪問策略 - 繼承 ApplicationEventPublisher ,提供強大的事件機制 - 擴充套件 ResourceLoader,可以用來載入多個 Resource,可以靈活訪問不同的資源 - 對 Web 應用的支援 ### ApplicationContext 體系結構 先來看看 ApplicationContext 介面的繼承關係
可以看到 ApplicationContext 除了繼承 BeanFactory 介面以外,還繼承了 MessageSource、ApplicationEventPublisher、ResourceLoader 等介面 簡單描述幾個介面: - `org.springframework.core.io.ResourceLoader`,資源載入介面,用於訪問不同的資源 - `org.springframework.context.ApplicationEventPublisher`,事件釋出器介面,支援釋出事件 - `org.springframework.context.MessageSource`,訊息資源介面,提供國際化的標準訪問策略 - `org.springframework.core.env.EnvironmentCapable`,環境暴露介面,Spring 應用上下文支援多環境的配置 - `org.springframework.context.ApplicationContext`,Spring 應用上下文,僅可讀 - `org.springframework.context.ConfigurableApplicationContext`,Spring 應用上下文,支援配置相關屬性 接下來我們來看看它們的實現類的繼承關係(部分)
簡單描述上面幾個關鍵的類: - `org.springframework.context.support.AbstractApplicationContext`,Spring 應用上下文的抽象類,實現了大部分功能,提供骨架方法交由子類去實現 - `org.springframework.web.context.ConfigurableWebApplicationContext`,可配置的 Spring 應用上下文介面,支援 Web 應用 - `org.springframework.context.support.AbstractRefreshableConfigApplicationContext`,支援設定 XML 檔案 - `org.springframework.web.context.support.AbstractRefreshableWebApplicationContext`,支援 Web 應用 - `org.springframework.web.context.support.AnnotationConfigWebApplicationContext`,支援 Web 應用,可以設定 XML 檔案,並可以掃描註解下面的 Bean - `org.springframework.context.annotation.AnnotationConfigApplicationContext`,支援掃描註解下面的 Bean - `org.springframework.web.context.support.ClassPathXmlApplicationContext`,支援設定 XML 檔案,也可以從 classpath 下面掃描相關資源 ApplicationContext 的子類比較多,主要根據支援 Web、支援註解、支援 XML 檔案三個功能進行區分,我們大致瞭解每個實現類的作用即可。其中基本的實現都是在 **AbstractApplicationContext** 這個抽象類中完成的,在它的 `refresh()` 方法體現了 Spring 應用上下文的生命週期。`AbstractApplicationContext#refresh()` 這個方法可以說是 Spring 應用上下文的準備階段,在使用 Spring 時該方法會被呼叫,本文就圍繞它進行展述。 可以先看到我的另一篇文章[《精盡Spring MVC原始碼分析 - WebApplicationContext 容器的初始化》](https://www.cnblogs.com/lifullmoon/p/14131802.html),在 Spring MVC 啟動過程中,建立 Spring 應用上下文後會呼叫其 `refresh()` 方法進行重新整理,讓 Spring 應用上下文準備就緒。 ### AbstractApplicationContext `org.springframework.context.support.AbstractApplicationContext`,Spring 應用上下文的抽象類,實現了大部分功能,提供骨架方法交由子類去實現 先來看看它的相關屬性 ```java public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource"; public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor"; public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster"; static { // Eagerly load the ContextClosedEvent class to avoid weird classloader issues // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.) ContextClosedEvent.class.getName(); } /** Unique id for this context, if any. */ private String id = ObjectUtils.identityToString(this); /** Display name. */ private String displayName = ObjectUtils.identityToString(this); /** 父應用上下文 */ @Nullable private ApplicationContext parent; /** 當前應用上下文的環境 */ @Nullable private ConfigurableEnvironment environment; /** BeanFactory 的處理器 */ private final List beanFactoryPostProcessors = new ArrayList<>(); /** 啟動時間 */ private long startupDate; /** 是否處於啟用狀態 */ private final AtomicBoolean active = new AtomicBoolean(); /** 是否處於關閉狀態 */ private final AtomicBoolean closed = new AtomicBoolean(); /** 啟動和銷燬時的鎖物件 */ private final Object startupShutdownMonitor = new Object(); /** 鉤子函式,用於 JVM 關閉時的回撥 */ @Nullable private Thread shutdownHook; /** ResourcePatternResolver used by this context. */ private ResourcePatternResolver resourcePatternResolver; /** LifecycleProcessor for managing the lifecycle of beans within this context. */ @Nullable private LifecycleProcessor lifecycleProcessor; /** MessageSource we delegate our implementation of this interface to. */ @Nullable private MessageSource messageSource; /** 事件廣播器 */ @Nullable private ApplicationEventMulticaster applicationEventMulticaster; /** 事件監聽器 */ private final Set> applicationListeners = new LinkedHashSet<>(); /** 早期(Spring 應用上下文還未就緒)註冊的時間監聽器 */ @Nullable private Set> earlyApplicationListeners; /** 早期(Spring 應用上下文還未就緒)釋出的事件 */ @Nullable private Set earlyApplicationEvents; public AbstractApplicationContext() { this.resourcePatternResolver = getResourcePatternResolver(); } public AbstractApplicationContext(@Nullable ApplicationContext parent) { this(); setParent(parent); } } ``` 屬性不多,上面都有註釋 #### publishEvent 方法 `publishEvent(ApplicationEvent event)` 方法,釋出事件,因為它繼承了 ApplicationEventPublisher 事件釋出器,如下: ```java @Override public void publishEvent(ApplicationEvent event) { publishEvent(event, null); } protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { // 如果不是 ApplicationEvent 型別的事件,則封裝成 PayloadApplicationEvent applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType(); } } // Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { // 廣播該事件 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... // 父容器也要釋出事件 if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } } ``` 過程如下: 1. 如果不是 ApplicationEvent 型別的事件,則封裝成 PayloadApplicationEvent 2. 如果 `earlyApplicationEvents` 不為 `null`,則表示當前 Spring 應用上下文正在處於重新整理階段,還沒有準備就緒,則先將這個早期事件新增至 `earlyApplicationEvents`;否則,Spring 應用上下文已經準備就緒了,此時就對該事件進行廣播 3. 如果存在父應用上下文,也需要進行廣播 上面的第 `2` 步中的 `earlyApplicationEvents` 如果不為 `null` ,為什麼 Spring 應用上下文還沒有準備就緒呢?答案會在後面體現 #### addBeanFactoryPostProcessor 方法 `addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor)` 方法,新增 BeanFactoryPostProcessor 處理器,如下: ```java @Override public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) { Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null"); this.beanFactoryPostProcessors.add(postProcessor); } ``` 直接往 `beanFactoryPostProcessors` 新增,BeanFactoryPostProcessor 處理器用於在 Spring 應用上下文重新整理階段對建立好的 BeanFactory 進行字尾處理 #### addApplicationListener 方法 `addApplicationListener(ApplicationListener listener)` 方法,新增事件監聽器,如下: ```java @Override public void addApplicationListener(ApplicationListener listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } this.applicationListeners.add(listener); } ``` 如果事件廣播器不為空則將該監聽器新增進去,然後再新增到本地的 `applicationListeners` 中 #### 【核心】refresh 方法 `refresh()` 方法,Spring 應用上下文的重新整理,讓 Spring 應用上下文處於準備就緒狀態,如下: ```java /** * 重新整理上下文,在哪會被呼叫? * 在 **Spring MVC** 中,{@link org.springframework.web.context.ContextLoader#initWebApplicationContext} 方法初始化上下文時,會呼叫該方法 */ @Override public void refresh() throws BeansException, IllegalStateException { // <1> 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛 synchronized (this.startupShutdownMonitor) { // <2> 重新整理上下文環境的準備工作,記錄下容器的啟動時間、標記'已啟動'狀態、對上下文環境屬性進行校驗 prepareRefresh(); // <3> 建立並初始化一個 BeanFactory 物件 `beanFactory`,會加載出對應的 BeanDefinition 元資訊們 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // <4> 為 `beanFactory` 進行一些準備工作,例如新增幾個 BeanPostProcessor,手動註冊幾個特殊的 Bean prepareBeanFactory(beanFactory); try { // <5> 對 `beanFactory` 在進行一些後期的加工,交由子類進行擴充套件 postProcessBeanFactory(beanFactory); // <6> 執行 BeanFactoryPostProcessor 處理器,包含 BeanDefinitionRegistryPostProcessor 處理器 invokeBeanFactoryPostProcessors(beanFactory); // <7> 對 BeanPostProcessor 處理器進行初始化,並新增至 BeanFactory 中 registerBeanPostProcessors(beanFactory); // <8> 設定上下文的 MessageSource 物件 initMessageSource(); // <9> 設定上下文的 ApplicationEventMulticaster 物件,上下文事件廣播器 initApplicationEventMulticaster(); // <10> 重新整理上下文時再進行一些初始化工作,交由子類進行擴充套件 onRefresh(); // <11> 將所有 ApplicationListener 監聽器新增至 `applicationEventMulticaster` 事件廣播器,如果已有事件則進行廣播 registerListeners(); // <12> 設定 ConversionService 型別轉換器,**初始化**所有還未初始化的 Bean(不是抽象、單例模式、不是懶載入方式) finishBeanFactoryInitialization(beanFactory); // <13> 重新整理上下文的最後一步工作,會發布 ContextRefreshedEvent 上下文完成重新整理事件 finishRefresh(); } // <14> 如果上面過程出現 BeansException 異常 catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // <14.1> “銷燬” 已註冊的單例 Bean destroyBeans(); // <14.2> 設定上下文的 `active` 狀態為 `false` cancelRefresh(ex); // <14.3> 丟擲異常 throw ex; } // <15> `finally` 程式碼塊 finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... // 清除相關快取,例如通過反射機制快取的 Method 和 Field 物件,快取的註解元資料,快取的泛型型別物件,快取的類載入器 resetCommonCaches(); } } } ``` 整個過程比較長,每一個步驟都呼叫一個方法,過程如下: 1. 來個鎖,不然 `refresh()` 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛 2. **應用上下文啟動準備階段**,呼叫 `prepareRefresh()` 方法,說明:重新整理上下文環境的準備工作,記錄下容器的啟動時間、標記'已啟動'狀態、對上下文環境屬性進行校驗 3. **BeanFactory 建立階段**,呼叫 `obtainFreshBeanFactory()` 方法,說明:建立並初始化一個 BeanFactory 物件 `beanFactory`,會加載出對應的 BeanDefinition 元資訊們 4. **BeanFactory 準備階段**,呼叫 `prepareBeanFactory()` 方法,說明:為 `beanFactory` 進行一些準備工作,例如新增幾個 BeanPostProcessor,手動註冊幾個特殊的 Bean 5. **BeanFactory 後置處理階段**,呼叫 `postProcessBeanFactory(ConfigurableListableBeanFactory)` 方法,說明:對 `beanFactory` 在進行一些後期的加工,交由子類進行擴充套件 6. **BeanFactory 後置處理階段**,呼叫 `invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)` 方法,說明:執行 BeanFactoryPostProcessor 處理器,包含 BeanDefinitionRegistryPostProcessor 處理器 7. **BeanFactory 註冊 BeanPostProcessor 階段**,呼叫 `registerBeanPostProcessors(ConfigurableListableBeanFactory)` 方法,說明:對 BeanPostProcessor 處理器進行初始化,並新增至 BeanFactory 中 8. **初始化內建 Bean:MessageSource**,呼叫 `initMessageSource()` 方法,說明:設定上下文的 MessageSource 物件 9. **初始化內建 Bean:Spring 事件廣播器**,呼叫 `initApplicationEventMulticaster()` 方法,說明:設定上下文的 ApplicationEventMulticaster 物件,上下文事件廣播器 10. **Spring 應用上下文重新整理擴充套件階段**,呼叫 `onRefresh()` 方法,說明:重新整理上下文時再進行一些初始化工作,交由子類進行擴充套件 11. **Spring 事件監聽器註冊階段**,呼叫 `registerListeners()` 方法,說明:將所有 ApplicationListener 監聽器新增至 `applicationEventMulticaster` 事件廣播器,如果已有事件則進行廣播 12. **BeanFactory 初始化完成階段**,呼叫 `finishBeanFactoryInitialization(ConfigurableListableBeanFactory)` 方法,說明:設定 ConversionService 型別轉換器,**初始化**所有還未初始化的 Bean(不是抽象、單例模式、不是懶載入方式) 13. **應用上下文重新整理完成階段**,呼叫 `finishRefresh()` 方法,說明:重新整理上下文的最後一步工作,會發布 ContextRefreshedEvent 上下文完成重新整理事件 14. 如果上面過程出現 BeansException 異常 1. “銷燬” 已註冊的單例 Bean 2. 設定上下文的 `active` 狀態為 `false` 3. 丟擲異常 15. `finally` 程式碼塊,清除相關快取,例如通過反射機制快取的 Method 和 Field 物件,快取的註解元資料,快取的泛型型別物件,快取的類載入器 可以看到該過程分為許多階段,每個階段都非常關鍵,將在後續已經進行分析 #### registerShutdownHook 方法 `registerShutdownHook()` 方法,向 JVM 註冊一個鉤子函式,當 JVM 關閉時執行該函式,如下: ```java @Override public void registerShutdownHook() { if (this.shutdownHook == null) { // No shutdown hook registered yet. this.shutdownHook = new Thread() { @Override public void run() { synchronized (startupShutdownMonitor) { doClose(); } } }; // 為當前的 JVM 執行環境新增一個鉤子函式,用於關閉當前上下文 Runtime.getRuntime().addShutdownHook(this.shutdownHook); } } ``` 這個鉤子函式也就是呼叫了 `doClose()` 方法,用於關閉當前 Spring 應用上下文 #### close 方法 `close()` 方法,關閉當前 Spring 應用上下文,如下: ```java @Override public void close() { synchronized (this.startupShutdownMonitor) { doClose(); // If we registered a JVM shutdown hook, we don't need it anymore now: // We've already explicitly closed the context. if (this.shutdownHook != null) { try { Runtime.getRuntime().removeShutdownHook(this.shutdownHook); } catch (IllegalStateException ex) { // ignore - VM is already shutting down } } } } ``` 關閉當前 Spring 應用上下文,也是呼叫 `doClose()` 方法,同時如果存在鉤子函式則將其從 JVM 中移除,因為上面已經關閉了 #### doClose 方法 `doClose()` 方法,關閉當前 Spring 應用上下文,如下: ```java protected void doClose() { // Check whether an actual close attempt is necessary... if (this.active.get() && this.closed.compareAndSet(false, true)) { // Live Beans JMX 撤銷託管 LiveBeansView.unregisterApplicationContext(this); try { // Publish shutdown event. // 釋出當前 Spring 應用上下文關閉事件 publishEvent(new ContextClosedEvent(this)); } catch (Throwable ex) { logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex); } // Stop all Lifecycle beans, to avoid delays during individual destruction. if (this.lifecycleProcessor != null) { try { // 關閉 Lifecycle Beans this.lifecycleProcessor.onClose(); } catch (Throwable ex) { logger.warn("Exception thrown from LifecycleProcessor on context close", ex); } } // Destroy all cached singletons in the context's BeanFactory. // 銷燬所有的單例 Bean destroyBeans(); // Close the state of this context itself. // 關閉底層 BeanFactory 容器 closeBeanFactory(); // Let subclasses do some final clean-up if they wish... // 提供給子類去實現,用於清理相關資源 onClose(); // Reset local application listeners to pre-refresh state. if (this.earlyApplicationListeners != null) { this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Switch to inactive. this.active.set(false); } } ``` 主要做以下事情: 1. Live Beans JMX 撤銷託管 2. 釋出當前 Spring 應用上下文關閉事件 3. 銷燬所有的單例 Bean,呼叫 DefaultListableBeanFactory#destroySingletons() 方法 4. 關閉底層 BeanFactory 容器 5. 回撥 onClose() 方法 ### 1. 應用上下文啟動準備階段 AbstractApplicationContext#prepareRefresh() 方法,如下: ```java // AbstractApplicationContext.java protected void prepareRefresh() { // 設定啟動時間 this.startupDate = System.currentTimeMillis(); // 設定當前 ApplicationContext 的狀態 this.closed.set(false); this.active.set(true); // Initialize any placeholder property sources in the context environment. // 初始化 ApplicationContext 的 Environment(上下文環境)的相關屬性,交由子類去實現,如果是 Web 則會設定 ServletContext 和 ServletConfig initPropertySources(); // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties // 對屬性進行必要的驗證 getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners... if (this.earlyApplicationListeners == null) { this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { // Reset local application listeners to pre-refresh state. this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); } ``` 主要做了以下事情: 1. 設定啟動時間:startupDate 2. 設定 Spring 應用上下文的狀態標識:closed(false)、active(true) 3. 初始化 PropertySources - initPropertySources(),初始化 ApplicationContext 的 Environment(上下文環境)的相關屬性,交由子類去實現,如果是 Web 則會設定 ServletContext 和 ServletConfig 4. 校驗 Environment 中必須屬性 5. 初始化早期 Spring 事件集合 `earlyApplicationEvents`,注意這裡建立了一個空的集合,也就是不為 null,回到前面的 `publishEvent(...)` 方法,如果 `earlyApplicationEvents` 不為 null 則會新增到這個集合裡面,不會進行廣播。這一步的目的就是在 Spring 應用上下文還未完全就緒時,如果釋出了事件,則需要先儲存起來,等就緒後才進行廣播 ### 2. BeanFactory 建立階段 整個過程會建立一個 DefaultListableBeanFactory 物件作為底層 IoC 容器,然後從資原始檔或者根據指定路徑下 .class 檔案(標註了@ Component 註解)加載出所有的 BeanDefinition #### 2.1 obtainFreshBeanFactory 方法 AbstractApplicationContext#obtainFreshBeanFactory() 方法,如下: ```java protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); } ``` 這兩個方法都是抽象方法,交由子類實現,我們來看到 AbstractRefreshableApplicationContext 的實現 #### 2.2 refreshBeanFactory 方法 AbstractRefreshableApplicationContext#refreshBeanFactory() 方法,如下: ```java @Override protected final void refreshBeanFactory() throws BeansException { // 若已有 BeanFactory ,銷燬它的 Bean 們,並銷燬 BeanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 建立 DefaultListableBeanFactory 物件 DefaultListableBeanFactory beanFactory = createBeanFactory(); // 指定序列化編號 beanFactory.setSerializationId(getId()); // 定製 BeanFactory 相關屬性(是否允許 BeanDefinition 重複定義,是否允許迴圈依賴,預設都是允許) customizeBeanFactory(beanFactory); // 載入 BeanDefinition 們 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); } protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } } ``` 主要做以下事情: 1. 若已有 BeanFactory ,銷燬它的 Bean 們,並銷燬 BeanFactory 2. 建立 BeanFactory,DefaultListableBeanFactory 物件 3. 設定 BeanFactory Id 4. 定製 BeanFactory 相關屬性(是否允許 BeanDefinition 重複定義,是否允許迴圈依賴,預設都是允許) 5. 加載出 BeanDefinition 們 - `loadBeanDefinitions(DefaultListableBeanFactory beanFactory)` 方法,交由子類實現(主要是 XML 和 Annotation 的區別) 6. 關聯 BeanFactory 到 Spring 應用上下文(ApplicationContext) 上面第 `6` 步會將第 `2` 步建立的 DefaultListableBeanFactory 設定為 Spring 應用上下文的 BeanFactory 物件,也就可以通過 `getBeanFactory()` 獲取 我們再來看到 `loadBeanDefinitions(...)` 抽象方法的實現,主要為註解和 XML 的區別,先來看到 AbstractXmlApplicationContext 的實現 #### 2.3 loadBeanDefinitions 方法(XML) AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法,如下: ```java @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. // 建立 XmlBeanDefinitionReader 物件 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. // 對 XmlBeanDefinitionReader 進行環境變數的設定 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. // 對 XmlBeanDefinitionReader 進行設定,可以進行覆蓋 initBeanDefinitionReader(beanDefinitionReader); // 從 Resource 們中,載入 BeanDefinition 們 loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { // 從配置檔案 Resource 中,載入 BeanDefinition 們 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } // 從配置檔案地址中,載入 BeanDefinition 們 String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } } ``` 可以看到這裡建立了 [**《BeanDefinition 的載入階段(XML 檔案)》**](https://www.cnblogs.com/lifullmoon/p/14437305.html)這篇文章中講到的 XmlBeanDefinitionReader 資源解析器物件,然後通過它解析 XML 配置檔案,解析過程在之前的文章中已經分析過了。 > 配置檔案怎麼來的呢? > > 在 [**《精盡Spring MVC原始碼分析 - WebApplicationContext 容器的初始化》**](https://www.cnblogs.com/lifullmoon/p/14131802.html)的 ContextLoader#configureAndRefreshWebApplicationContext(...) 方法中可以看到,會將 `web.xml` 檔案中配置的 `contextConfigLocation` 設定到 Spring 應用上下文中 我們再來看到 AnnotationConfigWebApplicationContext 的實現 #### 2.3 loadBeanDefinitions 方法(註解) AnnotationConfigWebApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法,如下: ```java @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) { AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory); ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory); BeanNameGenerator beanNameGenerator = getBeanNameGenerator(); if (beanNameGenerator != null) { reader.setBeanNameGenerator(beanNameGenerator); scanner.setBeanNameGenerator(beanNameGenerator); beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator); } ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver(); if (scopeMetadataResolver != null) { reader.setScopeMetadataResolver(scopeMetadataResolver); scanner.setScopeMetadataResolver(scopeMetadataResolver); } if (!this.componentClasses.isEmpty()) { if (logger.isDebugEnabled()) { logger.debug("Registering component classes: [" + StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]"); } reader.register(ClassUtils.toClassArray(this.componentClasses)); } if (!this.basePackages.isEmpty()) { if (logger.isDebugEnabled()) { logger.debug("Scanning base packages: [" + StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]"); } // 掃描指定包路徑下 @Component 註解的 .class 檔案,會解析出 BeanDefinition 物件 scanner.scan(StringUtils.toStringArray(this.basePackages)); } String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { try { Class clazz = ClassUtils.forName(configLocation, getClassLoader()); if (logger.isTraceEnabled()) { logger.trace("Registering [" + configLocation + "]"); } reader.register(clazz); } catch (ClassNotFoundException ex) { if (logger.isTraceEnabled()) { logger.trace("Could not load class for config location [" + configLocation + "] - trying package scan. " + ex); } int count = scanner.scan(configLocation); if (count == 0 && logger.isDebugEnabled()) { logger.debug("No component classes found for specified class/package [" + configLocation + "]"); } } } } } protected ClassPathBeanDefinitionScanner getClassPathBeanDefinitionScanner(DefaultListableBeanFactory beanFactory) { return new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment()); } ``` 我們主要看到關鍵的一步,會建立一個 ClassPathBeanDefinitionScanner 掃描器物件,然後呼叫其 scan(String... basePackages) 方法去掃描指定包路徑下的 .class 檔案,整個掃描過程在 [**《BeanDefinition 的解析過程(面向註解)》**](https://www.cnblogs.com/lifullmoon/p/14451788.html) 這篇文章中已經分析過了 ### 3. BeanFactory 準備階段 AbstractApplicationContext#prepareBeanFactory(ConfigurableListableBeanFactory) 方法,如下: ```java protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 設定 ClassLoader 類載入器 beanFactory.setBeanClassLoader(getClassLoader()); // 設定 BeanExpressionResolver 表示式語言處理器,Spring 3 開始增加了對語言表示式的支援,例如可以使用 #{bean.xxx} 的形式來呼叫這個 Bean 的屬性值 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 新增一個預設的 PropertyEditorRegistrar 屬性編輯器 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); /* * 新增一個 BeanPostProcessor 處理器,ApplicationContextAwareProcessor,初始化 Bean 的**前置**處理 * 這個 BeanPostProcessor 其實是對幾種 Aware 介面的處理,呼叫其 setXxx 方法 * 可以跳到 AbstractAutowireCapableBeanFactory 的 initializeBean(...) 方法(呼叫 Bean 的初始化方法)中看看 */ beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 忽略 Aware 回撥介面作為依賴注入介面 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // 設定幾個自動裝配的特殊規則,當你自動注入下面這些型別的 Bean 時,注入的就是右邊的值 // 可以看到 ApplicationContext.class 對應當前物件 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. // 新增一個 BeanPostProcessor 處理器,ApplicationListenerDetector,用於裝飾監聽器 // 初始化 Bean 的時候,如果是 ApplicationListener 型別且為單例模式,則新增到 Spring 應用上下文 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 增加對 AspectJ 的支援,AOP 相關 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 註冊幾個 ApplicationContext 上下文預設的 Bean 物件 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } } ``` 主要做以下事情: 1. 設定 ClassLoader 類載入器 2. 設定 BeanExpressionResolver **表示式語言處理器**,Spring 3 開始增加了對語言表示式的支援,例如可以使用 #{bean.xxx} 的形式來獲取這個 Bean 的屬性值 3. 新增一個預設的 PropertyEditorRegistrar **屬性編輯器** - ResourceEditorRegistrar 4. 新增一個 BeanPostProcessor 處理器 - `ApplicationContextAwareProcessor`,相關 Aware 回撥介面的實現,呼叫其 setXxx 方法 5. 忽略 Aware 回撥介面作為依賴注入介面 6. 註冊 ResolvableDependency 物件 - BeanFactory、ResourceLoader、ApplicationEventPublisher 以及 ApplicationContext,依賴注入這幾個物件時注入的都是當前 Spring 應用上下文,在[**《@Autowired 等註解的實現原理》**](https://www.cnblogs.com/lifullmoon/p/14453011.html)這篇文章中有講到 7. 新增一個 BeanPostProcessor 處理器 - `ApplicationListenerDetector`,初始化 Bean 的時候,如果是 ApplicationListener 型別且為單例模式,則新增到 Spring 應用上下文 8. 新增一個 BeanPostProcessor 處理器 - LoadTimeWeaverAwareProcessor,增加對 AspectJ 的支援,AOP 相關 9. 註冊幾個單例物件 - Environment、SystemProperties(Java System Properties)、SystemEnvironment(OS 環境變數) ### 4. BeanFactory 後置處理階段 有序地執行所有 BeanFactoryPostProcessor(包括 BeanDefinitionRegistryPostProcessor)處理器,例如 `@Bean` 等註解定義的 Bean 的就是通過 BeanDefinitionRegistryPostProcessor 處理器接續出來的 #### 4.1 postProcessBeanFactory 方法 該抽象方法交由子類實現,例如 AbstractRefreshableWebApplicationContext#postProcessBeanFactory(ConfigurableListableBeanFactory) 方法,如下: ```java @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 新增 ServletContextAwareProcessor 到 BeanFactory 容器中, // 該 processor 實現 BeanPostProcessor 介面,主要用於將 ServletContext 傳遞給實現了 ServletContextAware 介面的 bean beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); // 忽略 ServletContextAware、ServletConfigAware,上面的 ServletContextAwareProcessor 已代替 beanFactory.ignoreDependencyInterface(ServletContextAware.class); beanFactory.ignoreDependencyInterface(ServletConfigAware.class); // 註冊 WEB 應用特定的域(scope)到 beanFactory 中,以便 WebApplicationContext 可以使用它們。 // 比如'request','session','globalSession','application' WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); // 註冊 WEB 應用特定的 Environment bean 到 beanFactory 中,以便 WebApplicationContext 可以使用它們 // 如:'contextParameters','contextAttributes' WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig); } ``` 新增 ServletContext 相關內容 #### 4.2 invokeBeanFactoryPostProcessors 方法 AbstractApplicationContext#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) 方法,如下: ```java protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 執行所有的BeanFactoryPostProcessor處理器 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) // 在 prepareBeanFactory() 方法中也有相同操作 if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } } ``` 這裡藉助於 PostProcessorRegistrationDelegate 這個類執行所有 BeanFactoryPostProcessor 處理器,對前面建立的 BeanFactory 進行後置處理 #### 4.3 invokeBeanFactoryPostProcessors 方法 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法,如下(方法比較長,可直接檢視下面的總結): ```java public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set processedBeans = new HashSet<>(); // <1> 執行當前 Spring 應用上下文和底層 BeanFactory 容器中的 BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor 們的處理 if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List regularPostProcessors = new ArrayList<>(); List registryProcessors = new ArrayList<>(); // <1.1> 先遍歷當前 Spring 應用上下文中的 `beanFactoryPostProcessors`,如果是 BeanDefinitionRegistryPostProcessor 型別則進行處理 for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; // 執行 registryProcessor.postProcessBeanDefinitionRegistry(registry); // 新增,以供後續執行其他 `postProcessBeanFactory(registry)` 方法 registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! // Separate between BeanDefinitionRegistryPostProcessors that implement // PriorityOrdered, Ordered, and the rest. // 臨時變數,用於臨時儲存 BeanFactory 容器中的 BeanDefinitionRegistryPostProcessor 物件 List currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. // <1.2> 獲取底層 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 型別的 Bean 們,遍歷進行處理 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 如果實現了 PriorityOrdered 介面,則獲取到對應的 Bean if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 初始化 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } // 排序 sortPostProcessors(currentRegistryProcessors, beanFactory); // 臨時儲存起來 registryProcessors.addAll(currentRegistryProcessors); // 執行 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // 清理 currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. // <1.3> 獲取底層 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 型別的 Bean 們,遍歷進行處理 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 如果實現了 Ordered 介面並且沒有執行過,則獲取到對應的 Bean if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { // Ordered型別 // 初始化 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } // 排序 sortPostProcessors(currentRegistryProcessors, beanFactory); // 臨時儲存起來 registryProcessors.addAll(currentRegistryProcessors); // 執行 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // 清理 currentRegistryProcessors.clear(); // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. boolean reiterate = true; while (reiterate) { reiterate = false; // <1.4> 獲取底層 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 型別的 Bean 們,遍歷進行處理 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 如果該 BeanDefinitionRegistryPostProcessors 在上述過程中沒有執行過,則獲取到對應的 Bean if (!processedBeans.contains(ppName)) { // 初始化 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } // 排序 sortPostProcessors(currentRegistryProcessors, beanFactory); // 臨時儲存起來 registryProcessors.addAll(currentRegistryProcessors); // 執行 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // 清理 currentRegistryProcessors.clear(); } // Now, invoke the postProcessBeanFactory callback of all processors handled so far. /* * <1.5> 上述執行完當前 Spring 應用上下文和底層 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 處理器中的 postProcessBeanDefinitionRegistry(registry) 方法後, * 接下來執行它們的 postProcessBeanFactory(beanFactory) 方法 * * 注意:BeanDefinitionRegistryPostProcessor 繼承 BeanFactoryPostProcessor 介面 */ invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); /* * <1.6> 這裡我們執行當前 Spring 應用上下文中 BeanFactoryPostProcessor 處理器(非 BeanDefinitionRegistryPostProcessors 型別)的 * postProcessBeanFactory(beanFactory) 方法 * * 例如:PropertyPlaceholderConfigurer、PropertySourcesPlaceholderConfigurer */ invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } // <2> 執行當前 Spring 應用上下文中的 BeanFactoryPostProcessor 處理器的 postProcessBeanFactory(beanFactory) 方法 else { // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! // <3> 獲取底層 BeanFactory 容器中所有 BeanFactoryPostProcessor 型別的 Bean 們 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, // Ordered, and the rest. List priorityOrderedPostProcessors = new ArrayList<>(); List orderedPostProcessorNames = new ArrayList<>(); List nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { // 上面已經執行過了則跳過 // skip - already processed in first phase above } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // PriorityOrdered priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { // Ordered orderedPostProcessorNames.add(ppName); } else { // nonOrder nonOrderedPostProcessorNames.add(ppName); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. // <3.1> PriorityOrdered 型別的 BeanFactoryPostProcessor 物件 // 排序 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); // 執行 invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered. // <3.2> Ordered 型別的 BeanFactoryPostProcessor 物件 List orderedPostProcessors = new ArrayList<>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } // 排序 sortPostProcessors(orderedPostProcessors, beanFactory); // 執行 invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors. // <3.2> nonOrdered 的 BeanFactoryPostProcessor 物件 List nonOrderedPostProcessors = new ArrayList<>(); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } // 無需排序,直接執行 invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have // modified the original metadata, e.g. replacing placeholders in values... beanFactory.clearMetadataCache(); } ``` 主要做以下事情: 1. 如果當前 Spring 應用上下文是 BeanDefinitionRegistry 型別,則執行當前 Spring 應用上下文中所有 BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor 的處理,以及底層 BeanFactory 容器中 BeanDefinitionRegistryPostProcessor 的處理,處理順序如下: 1. 當前 Spring 應用上下文中所有 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 2. 底層 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(優先順序:PriorityOrdered > Ordered > 無) 3. 當前 Spring 應用上下文和底層 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor#postProcessBeanFactory 4. 當前 Spring 應用上下文中所有 BeanFactoryPostProcessor#postProcessBeanFactory 2. 否則,執行當前 Spring 應用上下文中所有 BeanFactoryPostProcessor#postProcessBeanFactory 3. 執行底層 BeanFactory 容器中所有 BeanFactoryPostProcessor#postProcessBeanFactory,上面已經處理過的會跳過,執行順序和上面一樣:PriorityOrdered > Ordered > 無 總結:有序地執行所有 BeanFactoryPostProcessor(包括 BeanDefinitionRegistryPostProcessor)處理器 ### 5. BeanFactory 註冊 BeanPostProcessor 階段 將所有已加載出來的 BeanPostProcessor 型別的 BeanDefinition 通過依賴查詢獲取到 Bean 們,然後有序的新增至 BeanFactory 中 AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory) 方法,如下: ```java protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); } ``` 這裡也藉助於 PostProcessorRegistrationDelegate 這個類註冊所有 BeanPostProcessor 處理器,如下: ```java public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { // <1> 獲取所有的 BeanPostProcessor 型別的 beanName // 這些 beanName 都已經全部載入到容器中去,但是沒有例項化 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when // a bean is created during BeanPostProcessor instantiation, i.e. when // a bean is not eligible for getting processed by all BeanPostProcessors. // <2> 記錄所有的 BeanPostProcessor 數量,為什麼加 1 ?因為下面又添加了一個 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; // 註冊 BeanPostProcessorChecker,它主要是用於在 BeanPostProcessor 例項化期間記錄日誌 // 當 Spring 中高配置的後置處理器還沒有註冊就已經開始了 bean 的例項化過程,這個時候便會列印 BeanPostProcessorChecker 中的內容 beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered, Ordered, and the rest. // <3> 開始註冊 BeanPostProcessor // 實現了 `PriorityOrdered` 介面的 BeanPostProcessor 對應的 Bean 集合 List priorityOrderedPostProcessors = new ArrayList<>(); // MergedBeanDefinitionPostProcessor 型別對應的 Bean 集合 List internalPostProcessors = new ArrayList<>(); // 實現了 `Ordered` 介面的 BeanPostProcessor 對應的 beanName 集合 List orderedPostProcessorNames = new ArrayList<>(); // 沒有順序的 BeanPostProcessor 對應的 beanName 集合 List nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { // PriorityOrdered if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 呼叫 getBean(...) 方法獲取該 BeanPostProcessor 處理器的 Bean 物件 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } // Ordered else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } // 無序 else { nonOrderedPostProcessorNames.add(ppName); } } // First, register the BeanPostProcessors that implement PriorityOrdered. // 第一步,對所有實現了 PriorityOrdered 的 BeanPostProcessor 進行排序 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); // 進行註冊,也就是新增至 DefaultListableBeanFactory 中 registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement Ordered. // 第二步,獲取所有實現了 Ordered 介面的 BeanPostProcessor 對應的 Bean 們 List orderedPostProcessors = new ArrayList<>(); for (String ppName : orderedPostProcessorNames) { // 呼叫 getBean(...) 方法獲取該 BeanPostProcessor 處理器的 Bean 物件 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } // 對所有實現了 Ordered 的 BeanPostProcessor 進行排序 sortPostProcessors(orderedPostProcessors, beanFactory); // 進行註冊,也就是新增至 DefaultListableBeanFactory 中 registerBeanPostProcessors(beanFactory, orderedPostProcessors); // Now, register all regular BeanPostProcessors. // 第三步註冊所有無序的 BeanPostProcessor List nonOrderedPostProcessors = new ArrayList<>(); for (String ppName : nonOrderedPostProcessorNames) { // 呼叫 getBean(...) 方法獲取該 BeanPostProcessor 處理器的 Bean 物件 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } // 註冊,無需排序 registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // Finally, re-register all internal BeanPostProcessors. // 最後,註冊所有的 MergedBeanDefinitionPostProcessor 型別的 Bean 們 sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); // Re-register post-processor for detecting inner beans as ApplicationListeners, // moving it to the end of the processor chain (for picking up proxies etc). // 重新註冊 ApplicationListenerDetector(探測器),用於探測內部 ApplicationListener 型別的 Bean // 在完全初始化 Bean 後,如果是 ApplicationListener 型別且為單例模式,則新增到 Spring 應用上下文 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); } ``` 主要做以下事情: 1. 獲取所有 BeanPostProcessor 型別的 beanName 2. 新增 BeanPostProcessor - BeanPostProcessorChecker,用於列印日誌(所有 BeanPostProcessor 還沒有全部例項化就有 Bean 初始化完成) 3. 獲取所有 BeanPostProcessor 實現類(依賴查詢),新增至 BeanFactory 容器中(順序:PriorityOrdered > Ordered > 無) 4. 注意,第 `3` 步新增的 BeanPostProcessor 如果是 MergedBeanDefinitionPostProcessor 型別,會再次新增(先移除再新增,也就是將順序往後挪) 5. 重新新增 BeanPostProcessor - ApplicationListenerDetector,目的將其移至最後,因為這個後置處理器用於探測 ApplicationListener 型別的 Bean,需要保證 Bean 完全初始化,放置最後比較合適 > 對與上述第 `4` 步是否疑惑?我的理解是 MergedBeanDefinitionPostProcessor 主要是依賴注入的實現,需要保證當前 Spring Bean 的相關初始化工作已完成,然後再進行依賴注入 總結:將所有已加載出來的 BeanPostProcessor 型別的 BeanDefinition 通過依賴查詢獲取到 Bean 們,然後有序的新增至 BeanFactory 中 ### 6. 初始化內建 Bean:MessageSource AbstractApplicationContext#initMessageSource() 方法,如下: ```java protected void initMessageSource() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 如果當前上下文中包含名稱為 `messageSource` 的 Bean 物件 if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); // 如果有父 ApplicationContext,並且 `messageSource` 為 HierarchicalMessageSource 物件,分級處理的 MessageSource if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) { HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; if (hms.getParentMessageSource() == null) { // Only set parent context as parent MessageSource if no parent MessageSource registered already. // 如果 `messageSource` 沒有註冊父 MessageSource,則設定為父類上下文的的 MessageSource hms.setParentMessageSource(getInternalParentMessageSource()); } } if (logger.isTraceEnabled()) { logger.trace("Using MessageSource [" + this.messageSource + "]"); } } else { // Use empty MessageSource to be able to accept getMessage calls. // 使用空 MessageSource DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); if (logger.isTraceEnabled()) { logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); } } } ``` 初始化當前 Spring 應用上下文的 MessageSource 物件,MessageSource 物件和國際化文案相關,Spring 預設情況不提供國際化文案,但是 MessageSource Bean 物件(空實現)是存在的,在 Spring Boot 中有實現,參考 MessageSourceAutoConfiguration 自動裝配類 ### 7. 初始化內建 Bean:Spring 事件廣播器 AbstractApplicationContext#initApplicationEventMulticaster() 方法,如下: ```java protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 如果當前上下文中包含名稱為 `applicationEventMulticaster` 的 Bean 物件 if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); } else { // 沒有則新建 SimpleApplicationEventMulticaster,並將該 Bean 註冊至當前上下文 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); } } ``` 初始化當前 Spring 應用上下文的 ApplicationEventMulticaster 事件廣播器物件,Spring 預設情況下為 SimpleApplicationEventMulticaster 物件 ### 8.應用上下文重新整理擴充套件階段 AbstractApplicationContext#onRefresh() 方法,空方法,交由子類實現,如 AbstractRefreshableWebApplicationContext 的實現 ```java @Override protected void onRefresh() { this.themeSource = UiApplicationContextUtils.initThemeSource(this); } ``` Web 場景下的 Spring 應用上下文會初始化 ThemeSource 物件 ### 9. Spring 事件監聽器註冊階段 AbstractApplicationContext#registerListeners() 方法,如下: ```java protected void registerListeners() { // <1> 將當前 Spring 應用上下文已有的事件監聽器依次新增至事件廣播器 for (ApplicationListener listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! // <2> 從底層 BeanFactory 容器中獲取所有 ApplicationListener 型別的 beanName 們(還未初始化),然後依次新增至事件廣播器 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... //<3> 至此,已經完成將事件監聽器全部新增至事件廣播器,接下來將早期的事件通過該事件廣播器廣播到所有的事件監聽器 // 早期事件:在當前 Spring 應用上下文重新整理的過程中已經發布的事件(此時釋出不會被監聽到,因為事件監聽器才剛全部找到,需要到此處通過事件廣播器進行廣播) Set earlyEventsToProcess = this.earlyApplicationEvents; /** * 將 `earlyApplicationEvents` 置為 `null` * 這裡很關鍵!!!後續釋出的事件不再是早期事件,會立即被事件廣播器廣播。因為當前 Spring 應用中的事件廣播器已經就緒了,事件監聽器也都獲取到了(雖然還沒有初始化) * 不過在下面廣播的時候,如果事件監聽器能夠處理該事件,則會通過依賴注入的方式初始化該事件監聽器 */ this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { // 廣播該事件,能夠處理該事件的事件監聽器會被初始化 getApplicationEventMulticaster().multicastEvent(earlyEvent); } } } ``` 主要做以下事情: 1. 將當前 Spring 應用上下文已有的事件監聽器依次新增至事件廣播器 2. 從底層 BeanFactory 容器中獲取所有 ApplicationListener 型別的 beanName 們(還未初始化),然後依次新增至事件廣播器 3. 複製全部的 `earlyApplicationEvents` **早期事件**,然後將 `earlyApplicationEvents` 置為 `null` 4. 廣播**早期事件**,如果事件監聽器能夠處理該事件,則會通過依賴注入的方式初始化該事件監聽器 **早期事件**:在當前 Spring 應用上下文重新整理的過程中已經發布的事件(此時釋出不會被監聽到,因為事件監聽器才剛全部找到,需要到此處通過事件廣播器進行