專題四:Spring源碼初始化環境與BeanFactory

上文我們通過new ClassPathXmlApplicationContext("applicationContext.xml");這段代碼看了下Spring是如何將Xml里面內容注入到Java對象中,并通過context.getBean("jmUser");方式獲得了一個對象實例,而避開使用new 來耦合。今天我們就來看看Spring是如何做到的呢?

上圖是AbstractApplicationContext的類圖,dedug跟蹤這段代碼

 new ClassPathXmlApplicationContext("applicationContext.xml");

ClassPathXmlApplicationContext構造方法

/*** 根據xml路徑,創建一個ClassPathXmlApplicationContext實例* Create a new ClassPathXmlApplicationContext with the given parent,* loading the definitions from the given XML files.* @param configLocations array of resource locations* @param refresh whether to automatically refresh the context,* loading all bean definitions and creating all singletons.* Alternatively, call refresh manually after further configuring the context.* @param parent the parent context* @throws BeansException if context creation failed* @see #refresh()*/public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {// 調用父類構造方法,主要是初始化環境變量相關信息,核心代碼在 AbstractApplicationContext 類中super(parent);// 設置配置文件的位置 ApplicationContext的實現可能會使用默認的配置文件位置。setConfigLocations(configLocations);// 默認構造trueif (refresh) {// 進入核心方法refresh();}}

1、初始化環境變量相關信息

發現最終進入

	/*** Create a new AbstractApplicationContext with no parent.* 創建一個沒有父容器的AbstractApplicationContext的實例*/public AbstractApplicationContext() {//  返回一個 PathMatchingResourcePatternResolver(this)實例this.resourcePatternResolver = getResourcePatternResolver();}/*** Create a new AbstractApplicationContext with the given parent context.* @param parent the parent context*/public AbstractApplicationContext(@Nullable ApplicationContext parent) {this();// 將父容器復制給成員變量 parent,如果parent不為空且屬于ConfigurableEnvironment類型則合并環境setParent(parent);}

2、設置配置文件的位置

/*** Set the config locations for this application context.* <p>If not set, the implementation may use a default as appropriate.* 配置了配置文件的位置* 如果未設置配置位置,某些ApplicationContext的實現可能會使用默認的配置文件位置。* 例如,ClassPathXmlApplicationContext如果沒有指定配置位置,會嘗試查找類路徑下的applicationContext.xml文件。*/public void setConfigLocations(@Nullable String... locations) {if (locations != null) {Assert.noNullElements(locations, "Config locations must not be null");this.configLocations = new String[locations.length];for (int i = 0; i < locations.length; i++) {
//				getEnvironment().resolveRequiredPlaceholders(path),從路徑中解析展位福${}參數this.configLocations[i] = resolvePath(locations[i]).trim();}}else {this.configLocations = null;}}/*** Resolve the given path, replacing placeholders with corresponding* environment property values if necessary. Applied to config locations.* @param path the original file path* @return the resolved file path* @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)*/protected String resolvePath(String path) {return getEnvironment().resolveRequiredPlaceholders(path);}public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {return this.propertyResolver.resolveRequiredPlaceholders(text);}

3、進入refresh方法

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing. 1、初始化上下文信息prepareRefresh();// Tell the subclass to refresh the internal bean factory. 2、解析類Xml、初始化BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context. 	3、準備BeanFactory內容prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses. 4、擴展點加一:空實現,主要用于處理特殊Bean的后置處理器postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context. 	5、spring bean容器的后置處理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation. 	6、注冊bean的后置處理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.	7、初始化消息源initMessageSource();// Initialize event multicaster for this context.	8、初始化事件廣播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses. 9、擴展點加一:空實現;主要是在實例化之前做些bean初始化擴展onRefresh();// Check for listener beans and register them.	10、初始化監聽器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.	11、實例化:非蘭加載BeanfinishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.	 12、發布相應的事件通知finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

整個流程可以分為以下幾個主要步驟:

  1. 初始化上下文環境信息。
  2. 解析XML配置文件,創建并初始化BeanFactory
  3. 設置BeanFactory的類加載器,注冊一些默認的環境Bean。
  4. 提供擴展點用于對BeanFactory進行進一步的定制。
  5. 調用BeanFactory的后置處理器。
  6. 注冊Bean的后置處理器。
  7. 初始化消息源,用于國際化支持。
  8. 初始化事件廣播器,用于發布事件。
  9. 提供擴展點用于在刷新上下文時做一些特殊的初始化。
  10. 檢查并注冊監聽器Bean。
  11. 實例化所有剩余的單例Bean(非懶加載)。
  12. 發布相應的事件通知,表示上下文刷新完成。

步驟概覽

1. prepareRefresh()
prepareRefresh();

prepareRefresh()方法用于初始化上下文環境信息,包括設置啟動時間、活動狀態等基本屬性。它確保在刷新過程中,應用上下文處于正確的狀態。

2. obtainFreshBeanFactory()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

該方法解析XML配置文件,創建并初始化BeanFactory,并載入Bean定義。它是Spring應用上下文初始化的關鍵步驟之一。

3. prepareBeanFactory(beanFactory)
prepareBeanFactory(beanFactory);

此步驟設置BeanFactory的類加載器,并注冊一些默認的環境Bean,如類加載器、表達式解析器等。它確保BeanFactory在上下文中能夠正確工作。

4. postProcessBeanFactory(beanFactory)
postProcessBeanFactory(beanFactory);

這是一個擴展點,通常為空實現。開發者可以在子類中重寫該方法,對BeanFactory進行進一步的定制,如添加額外的Bean定義或修改現有的Bean定義。

5. invokeBeanFactoryPostProcessors(beanFactory)
invokeBeanFactoryPostProcessors(beanFactory);

該方法調用BeanFactory的后置處理器,這些處理器可以在Bean實例化之前對Bean定義進行修改或增加新的Bean定義。

6. registerBeanPostProcessors(beanFactory)
registerBeanPostProcessors(beanFactory);

在此步驟中,Spring注冊Bean的后置處理器,這些處理器會在Bean的創建過程中攔截并進行處理,如執行依賴注入和初始化回調等。

7. initMessageSource()
initMessageSource();

該方法初始化消息源,用于支持國際化(i18n)。它允許應用程序根據用戶的語言環境顯示不同的消息。

8. initApplicationEventMulticaster()
initApplicationEventMulticaster();

Spring使用事件廣播器來發布和監聽應用程序事件。該方法初始化事件廣播器,確保事件能夠在應用上下文中正確傳播。

9. onRefresh()
onRefresh();

這是另一個擴展點,通常為空實現。開發者可以在子類中重寫該方法,在刷新上下文時執行一些特殊的初始化操作。

10. registerListeners()
registerListeners();

該方法檢查并注冊監聽器Bean,用于監聽和處理應用程序事件。

11. finishBeanFactoryInitialization(beanFactory)
finishBeanFactoryInitialization(beanFactory);

此步驟實例化所有剩余的單例Bean(非懶加載)。它確保所有Bean都已準備就緒,可以在應用程序中使用。

12. finishRefresh()
finishRefresh();

最后,Spring發布相應的事件通知,表示上下文刷新已完成。此步驟通常包括發布ContextRefreshedEvent事件,通知所有監聽器上下文已刷新。

總結

本章主要通過斷點源碼,一步步跟蹤到refresh方法,然后整體跟蹤了refresh的具體步驟,每一步大概干了什么內容,后面我們將一個一個方法深入討論,具體做了什么?預留了什么擴展點。我們在開發中怎么去使用這些擴展點。以及后面SpringBoot和SpringCloud是怎樣利用這些擴展點給我么提供開箱即用的功能的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/37365.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37365.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37365.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【TB作品】智能臺燈控制器,ATMEGA128單片機,Proteus仿真

題目 8 &#xff1a;智能臺燈控制器 基于單片機設計智能臺燈控制器&#xff0c;要求可以調節 LED 燈的亮度&#xff0c;實現定時開啟與關閉&#xff0c; 根據光照自動開啟與關閉功能。 具體要求如下&#xff1a; &#xff08;1&#xff09;通過 PWM 功能調節 LED 燈亮度&#x…

【本地調試】使用 Nginx 和 Hosts 文件實現本地開發調試請求轉發

可以按照以下 nginx 配置來設置&#xff0c;通過 nginx 和 host 將網頁的請求轉發到本地的后端服務器&#xff0c;以方便本地開發調試 一、nginx 配置 worker_processes 1;events {worker_connections 1024; }http {include mime.types;default_type application/js…

【Python】 數據分析中的常見統計量:中位數

那年夏天我和你躲在 這一大片寧靜的海 直到后來我們都還在 對這個世界充滿期待 今年冬天你已經不在 我的心空出了一塊 很高興遇見你 讓我終究明白 回憶比真實精彩 &#x1f3b5; 王心凌《那年夏天寧靜的海》 中位數&#xff08;Median&#xff09;是統計學…

深入淺出3D感知中的優化與基于學習的技術1(原創系列)

近期幾乎看了所有有關NERF技術論文&#xff0c;本身我研究的領域不在深度學習技術方向&#xff0c;是傳統的機器人控制和感知。所以總結了下這部分基于學習的感知技術&#xff0c;會寫一個新的系列教程講解這部分三維感知技術的發展到最新的技術細節&#xff0c;并支持自己最近…

娛樂圈發生震動,AI大模型技術已經取代了SNH48的小偶像?

自2023年以來&#xff0c;全球都被包裹在AI的驚天大潮之中&#xff0c;所有行業都在主動或被動地迎接改變。目前&#xff0c;各行業已經有大量公司正在把AI作為自身發展的最佳路徑。其中&#xff0c;娛樂行業作為最被人們熟知的行業也在面對AI的發展時&#xff0c;發生著巨大變…

解析Java中1000個常用類:Currency類,你學會了嗎?

在線工具站 推薦一個程序員在線工具站:程序員常用工具(http://cxytools.com),有時間戳、JSON格式化、文本對比、HASH生成、UUID生成等常用工具,效率加倍嘎嘎好用。程序員資料站 推薦一個程序員編程資料站:程序員的成長之路(http://cxyroad.com),收錄了一些列的技術教程…

解析connectionReset異常的原因與解決方案

解析connectionReset異常的原因與解決方案 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天我們將深入探討Java中connectionReset異常的原因及其解決方案。這…

遙遠星辰中的覺醒:超大質量黑洞的蘇醒與人類的未來

遙遠星辰中的覺醒&#xff1a;超大質量黑洞的蘇醒與人類的未來 在浩渺無垠的宇宙中&#xff0c;星辰的閃爍仿佛是時間的漣漪&#xff0c;穿越億萬年的距離&#xff0c;抵達我們的眼眸。而在這片星辰大海的深處&#xff0c;一個驚人的現象正在悄然上演——距離地球3.6億光年之遙…

Unity獲取剪切板內容粘貼板圖片文件文字

最近做了一個發送消息的unity項目&#xff0c;需要訪問剪切板里面的圖片文字文件等&#xff0c;翻遍了網上的東西&#xff0c;看了不是需要導入System.Windows.Forms&#xff08;關鍵導入了unity還不好用&#xff0c;只能用在純c#項目中&#xff09;&#xff0c;所以我看了下py…

GMSB文章九:微生物的相關關系組間波動

歡迎大家關注全網生信學習者系列&#xff1a; WX公zhong號&#xff1a;生信學習者Xiao hong書&#xff1a;生信學習者知hu&#xff1a;生信學習者CDSN&#xff1a;生信學習者2 介紹 計算配對微生物在組間的相關關系波動情況進而評估不同分組的微生物狀態。secom_linear 函數…

線性表與順序存儲結構(下)

前言 接上文&#xff08;線性表與順序存儲結構&#xff08;上&#xff09;&#xff09;。 這些順序存儲結構的方法在順序表上下卷中已經提到過&#xff0c;但是有些許不同&#xff0c;可以為理解順序表提供更豐富的視角。&#xff08;不過最主要的區別在于順序表上下卷中的順…

機器人關節 viscous friction與結構阻尼

Viscous Friction&#xff08;粘性摩擦&#xff09; 定義&#xff1a;Viscous friction&#xff0c;也被稱為粘性摩擦或粘滯摩擦&#xff0c;是機器人關節在運動過程中由于接觸面之間的相互作用而產生的摩擦力。這種摩擦力與關節的運動速度有關&#xff0c;通常表現為速度越大&…

HarmonyOS開發實戰:分布式文件系統-hmdfs

分布式文件系統提供跨設備的文件訪問能力&#xff0c;適用于如下場景&#xff1a; 兩臺設備組網&#xff0c;A 設備可以無感讀取和修改 B 設備的文件。 邊緣服務器可以自動同步組網中多個嵌入式設備中的文件數據。 hmdfs 在分布式軟總線動態組網的基礎上&#xff0c;為網絡上…

Ubuntu添加系統字體

&#xff08;2024.6.30&#xff09; 系統字體保存路徑在/usr/share/fonts下&#xff0c;如果此目錄下缺少字體&#xff0c;則使用其他可視化api&#xff08;如Python的pygame庫&#xff09;的默認配置時可能會出現亂碼問題。 往Ubuntu中添加字體的方法 方法一&#xff1a;手…

Ant Design Vue:如何提升你的前端開發效率?

目錄 1. Ant Design Vue 簡介 1.1 特性概覽 1.2 安裝與配置 2. 常用組件及使用示例 2.1 Button 按鈕 2.2 Form 表單 2.3 Table 表格 2.4 Modal 對話框 3. 常見問題及解決方案 3.1 組件無法渲染 問題描述 解決方案 3.2 表單驗證失效 問題描述 解決方案 3.3 表格…

Python | 計算位渦平流項

寫在前面 最近忙著復習、考試…都沒怎么空敲代碼&#xff0c;還得再準備一周考試。。。等考完試再慢慢更新了&#xff0c;今天先來淺更一個簡單但是使用的python code 在做動力機制分析時&#xff0c;我們常常需要借助收支方程來診斷不同過程的貢獻&#xff0c;其中最常見的一…

51單片機-點亮LED燈

目錄 新建項目選擇型號添加新文件到該項目設置字體和utf-8編碼二極管如何區分正負極原理&#xff1a;CPU通過寄存器來控制硬件電路 用P2寄存器的值控制第一個燈亮進制轉換編譯查看P2寄存器的地址生成HEX文件把代碼下載到單片機中 新建項目 選擇型號 stc是中國生產的、這個里面…

token登錄比密碼登錄有什么優勢嗎

token登錄比密碼登錄有什么優勢嗎 使用令牌&#xff08;Token&#xff09;登錄相比于密碼登錄具有一些優勢&#xff0c;包括&#xff1a; 安全性&#xff1a;令牌通常采用加密技術&#xff0c;使得它們更難以被盜取或猜測。相比之下&#xff0c;密碼存在被猜測、破解或被暴力攻…

解決瀏覽器兼容性問題的方法

解決瀏覽器兼容性問題的方法 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天我們來探討如何解決網頁開發中常見的瀏覽器兼容性問題。隨著互聯網技術的發展&…

java中輸入輸出流的繼承關系

在 Java 中,輸入輸出流的繼承關系主要圍繞兩個抽象基類展開:字節流基類 InputStream 和 OutputStream,以及字符流基類 Reader 和 Writer。這些類形成了 Java I/O 系統的基礎,提供了豐富的子類以適應不同的輸入輸出需求。 字節流 字節流用于處理原始的二進制數據。 Input…