Spring源碼二十:Bean實例化流程三

上一篇Spring源碼十九:Bean實例化流程二中,我們主要討論了單例Bean創建對象的主要方法getSingleton了解到了他的核心流程無非是:通過一個簡單工廠的getObject方法來實例化bean,當然spring在實例化前后提供了擴展如:beforeSingletonCreation與afterSingletonCreate,同樣為了提供性能會將實例化后的單例bean放入緩存中;又因為spring設計之初存在三級緩存,所以在放入緩存的時候又會將其他兩次的緩存清除。

簡單的回憶了之前的內容,我們發現還有一個很重要的點我們沒有說到那就是怎么通過簡單工廠來創建實例對象的,這一篇咱們詳細討論一下:


createBean

	/*** Central method of this class: creates a bean instance, 創建bean實例對象* populates the bean instance, applies post-processors, etc. 填充bean實例、應用后置處理器* @see #doCreateBean*/@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.// 判斷需要創建的bean是否可以實例化、是否可以通過當前類加載器加載Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.// 準備bean中的方法覆蓋try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.// 給BeanPostProcessors一個返回代理而不是目標bean實例的機會。Object bean = resolveBeforeInstantiation(beanName, mbdToUse);// 如果bean配置類后置處理器PostProcessor,則這里返回一個proxy代理對象if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {// bean實例對象創建方法Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

因為lockup-method屬性與repliace-methon配置屬性,現在基本上沒有使用場景,而resolveBeanClass與preprareMethodOverrides是為了是實現這個兩個方法而生的,所以我們直接來看 resolveBeforeInstantiation方法。

resolveBeforeInstantiation

@Nullableprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {// BeanPostProcessor前置處理方法bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {// BeanPostProcessor后置處理方法bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;}public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}

InstantiationAwareBeanPostProcessorBeanPostProcessor 的一個子接口,提供了以下方法,用于在 Bean 實例化的不同階段進行干預:

  • postProcessBeforeInstantiation(Class<?> beanClass, String beanName): 在 Bean 實例化之前調用。
  • postProcessAfterInstantiation(Object bean, String beanName): 在 Bean 實例化之后調用。
  • postProcessProperties(PropertyValues pvs, Object bean, String beanName): 在 Bean 的屬性設置之前調用。

這些方法提供了在 Bean 實例化過程中進行自定義邏輯處理的機會,可以用于 Bean 的替換、屬性的預處理等操作。

示例代碼:

public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {if ("myBean".equals(beanName)) {System.out.println("Before instantiation of " + beanName);// 可以返回一個代理對象或自定義的 Bean 實例}return null; // 返回 null 表示繼續默認的實例化過程}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) {System.out.println("After instantiation of " + beanName);return true; // 返回 true 表示繼續進行屬性設置}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {System.out.println("Processing properties for " + beanName);return pvs; // 可以修改屬性值}
}

InstantiationAwareBeanPostProcessor 擴展了 BeanPostProcessor 的功能,提供了在 Bean 實例化的不同階段進行干預的能力。通過實現 InstantiationAwareBeanPostProcessor 接口,開發人員可以在 Bean 實例化過程中插入自定義邏輯,實現更靈活的 Bean 管理和控制。

實例化與初始化

為了更好地理解 BeanPostProcessorInstantiationAwareBeanPostProcessor 的區別,我們需要明確實例化和初始化的概念。

  • 實例化:實例化是從零到一創建一個 Bean 的過程,即通過調用構造函數生成 Bean 的實例。
  • 初始化:初始化是在 Bean 實例化之后進行的配置過程,包括屬性注入、調用初始化方法等。

在 Spring 容器中,Bean 的生命周期大致分為以下幾個階段:

  1. 實例化:通過調用構造函數創建 Bean 實例。
  2. 屬性注入:將依賴的屬性注入到 Bean 中。
  3. 初始化:調用自定義的初始化方法,進行額外的配置。

BeanPostProcessor 與 InstantiationAwareBeanPostProcessor 的區別

  • 作用階段

    • BeanPostProcessor 主要作用于初始化階段,即在 Bean 的屬性已經注入之后進行處理。
    • InstantiationAwareBeanPostProcessor 作用于實例化階段和屬性注入階段,允許在 Bean 實例化之前、之后以及屬性注入之前進行處理。
  • 用途

    • BeanPostProcessor 常用于在 Bean 初始化之前和之后執行一些通用的處理邏輯,如代理增強、配置驗證等。
    • InstantiationAwareBeanPostProcessor 常用于在 Bean 實例化過程中執行一些特殊的處理邏輯,如提前終止 Bean 創建、動態生成代理對象、修改屬性注入邏輯等。

這個方法是在 Bean 初始化后應用所有注冊的 BeanPostProcessorpostProcessAfterInitialization 方法,其設計和實現反映了 Spring 框架中依賴注入和面向切面編程的核心理念。

Spring Bean 生命周期管理

在 Spring 框架中,Bean 的生命周期經歷了多個階段,包括實例化、依賴注入、初始化和銷毀等。applyBeanPostProcessorsAfterInitialization 方法所處的階段是在 Bean 初始化之后,即在所有屬性被設置后,執行自定義的后處理邏輯。

BeanPostProcessor 接口作用

BeanPostProcessor 接口定義了在 Bean 初始化前后可以插入自定義邏輯的能力。Spring 容器在創建 Bean 的過程中,會檢查是否注冊了 BeanPostProcessor,如果有,則會在相應的階段調用其方法。其中,postProcessAfterInitialization 方法是在 Bean 初始化完成后被調用的,允許開發者對 Bean 進行額外的處理或修改。

applyBeanPostProcessorsAfterInitialization 方法分析

  1. 初始化結果對象:方法開始時,首先將 result 對象初始化為 existingBean,即當前的 Bean 實例。這個 existingBean 是在容器中已經完成初始化的對象。

  2. 遍歷處理器列表:方法接著遍歷所有注冊的 BeanPostProcessor,對每一個后處理器調用其 postProcessAfterInitialization 方法。

    • 每個處理器可以在方法內部執行任何與 Bean 相關的操作,例如添加代理、執行驗證、修改屬性等。
    • 如果某個處理器返回 null,則表示不需要進一步處理,直接返回當前的 result 對象。
  3. 返回處理后的結果:最終返回經過所有后處理器處理后的 result 對象。這個對象可能是原始的 existingBean,也可能是經過多個處理器處理后的新對象。

技術原理分析

  • 面向切面編程(AOP)的應用:通過 BeanPostProcessor 接口,Spring 實現了 AOP 的一種簡單形式。開發者可以在 Bean 初始化后插入切面邏輯,例如添加事務、日志等。

  • 依賴注入的增強:允許在 Bean 初始化后對依賴關系進行增強或修改,以適應不同的運行時需求。

  • 靈活性與可擴展性:applyBeanPostProcessorsAfterInitialization 方法展示了 Spring 框架在管理 Bean 生命周期時的高度靈活性和可擴展性。開發者可以通過注冊自定義的 BeanPostProcessor 實現特定的業務邏輯,而不必修改現有的 Bean 實現代碼。

applyBeanPostProcessorsAfterInitialization 方法在 Spring 框架中扮演了重要角色,通過它,開發者可以在 Bean 初始化完成后添加自定義邏輯,擴展和定制應用程序的行為。理解這個方法的工作原理和技術實現,有助于深入理解 Spring 容器的工作機制,提升對 Bean 生命周期管理的控制和應用開發的靈活性。

總結

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

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

相關文章

第5章-組合序列類型

#全部是重點知識&#xff0c;必須會。 了解序列和索引|的相關概念 掌握序列的相關操作 掌握列表的相關操作 掌握元組的相關操作 掌握字典的相關操作 掌握集合的相關操作1&#xff0c;序列和索引 1&#xff0c;序列是一個用于存儲多個值的連續空間&#xff0c;每一個值都對應一…

升級之道:精通Conda的自我升級藝術

升級之道&#xff1a;精通Conda的自我升級藝術 引言 Conda是Python和其他科學計算語言的強大包管理器&#xff0c;它不僅管理著包的安裝和依賴&#xff0c;還負責自身的更新。隨著開源社區的不斷發展&#xff0c;Conda定期發布新版本以修復已知問題、增加新功能和提高性能。本…

[面試愛問] https 的s是什么意思,有什么作用?

HTTPS 中的 "S" 代表 "Secure"&#xff0c;即安全的意思。HTTPS&#xff08;全稱是 HyperText Transfer Protocol Secure&#xff09;是HTTP&#xff08;HyperText Transfer Protocol&#xff09;的安全版本&#xff0c;主要作用是為互聯網通信提供安全保護…

靈活多變的對象創建——工廠方法模式(Python實現)

1. 引言 大家好&#xff0c;又見面了&#xff01;在上一篇文章中&#xff0c;我們聊了聊簡單工廠模式&#xff0c;今天&#xff0c;我們要進一步探討一種更加靈活的工廠設計模式——工廠方法模式。如果說簡單工廠模式是“萬能鑰匙”&#xff0c;那工廠方法模式就是“變形金剛”…

生成式人工智能:助攻開發者還是取代開發者?

引言 近年來&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;在軟件開發領域掀起了一場革命&#xff0c;為開發者帶來了全新的工具和可能性。從代碼生成、錯誤檢測到自動化測試&#xff0c;AI正在以各種方式改變著開發者的工作方式。然而&#xff0c;這也引發了人們對開…

Python采集京東標題,店鋪,銷量,價格,SKU,評論,圖片

京東的許多數據是通過 JavaScript 動態加載的&#xff0c;包括銷量、價格、評論和評論時間等信息。我們無法僅通過傳統的靜態網頁爬取方法獲取到這些數據。需要使用到如 Selenium 或 Pyppeteer 等能夠模擬瀏覽器行為的工具。 另外&#xff0c;京東的評論系統是獨立的一個系統&a…

offer題目33:判斷是否是二叉搜索樹的后序遍歷序列

題目描述&#xff1a;輸入一個整數數組&#xff0c;判斷該數組是不是某二叉搜索樹的后序遍歷結果。如果是則返回true,否則返回false。假設輸入的數組的任意兩個數字都互不相同。例如&#xff0c;輸入數組{5,7,6,9,11,10,8},則返回true,&#xff0c;因為這個整數是下圖二叉搜索樹…

c++內存管理(上)

目錄 引入 分析 說明 C語言中動態內存管理方式 C內存管理方式 new/delete操作內置類型 new和delete操作自定義類型 引入 我們先來看下面的一段代碼和相關問題 int globalVar 1; static int staticGlobalVar 1; void Test() { static int staticVar 1; int localVar 1…

集訓day3:并查集

一、目錄 1.并查集模版 2.并查集的理解和應用 二、正文 1.并查集模版 P3367 【模板】并查集 - 洛谷 | 計算機科學教育新生態 (luogu.com.cn) 2.并查集的理解與應用 (1).并查集與聯通塊數量 P1197 [JSOI2008] 星球大戰 - 洛谷 | 計算機科學教育新生態 (luogu.com.cn) P1656 炸…

數圖助推朝陽佳惠遼寧華聯開啟數字化導航、精細化管理新紀元!

近期&#xff0c;遼寧省著名零售企業朝陽佳惠與遼寧華聯&#xff0c;秉持創新精神&#xff0c;大膽嘗試&#xff0c;在品類空間管理方面推出了創新舉措。引入了先進的數圖可視化陳列管理系統&#xff0c;通過智能化、直觀化的方式優化商品布局。此舉不僅大幅提高了商品管理的效…

去除各種軟件彈窗教程

清羽彈窗 在mutil/OnlineDialog/onPostExecute前 添加return-void Arm彈窗 第一步&#xff0c;提取安裝包 第二步&#xff0c;搜索代碼Ljava/io/DataOutputStream;->flush()V 第三步&#xff0c;往上看找到 .registers 10 在下面加return-void 云注入彈窗 第一種方法:dex搜…

Sql 導入到 Excel 工具

Sql 導入到 Excel 工具 這個VBA宏的步驟如下&#xff1a; 通過文件對話框選擇SQL文件。讀取文件內容。解析文件中的每一行&#xff0c;如果包含“insert into”&#xff0c;則提取表名。檢查是否已經存在以表名命名的工作表&#xff0c;如果不存在則創建新的工作表。將數據插…

element-ui封裝分頁組件:實現首頁、上一頁、下一頁、末頁、跳轉按鈕

首頁、上一頁、下一頁、末頁、跳轉按鈕 因為el-pagination只有一個插槽&#xff0c;所以通過兩個el-pagination插槽分別加入首頁、末頁按鈕&#xff0c;再拼接這兩個el-pagination的方式來實現首頁、末頁按鈕跳轉按鈕不用加事件&#xff0c;如果el-pagination修改了前往的頁數…

【work】AI八股-神經網絡相關

Deep-Learning-Interview-Book/docs/深度學習.md at master amusi/Deep-Learning-Interview-Book GitHub 網上相關總結&#xff1a; 小菜雞寫一寫基礎深度學習的問題&#xff08;復制大佬的&#xff0c;自己復習用&#xff09; - 知乎 (zhihu.com) CV面試問題準備持續更新貼 …

VOI(Virtual Operating System Infrastructure,虛擬操作系統基礎架構)

VOI&#xff08;Virtual Operating System Infrastructure&#xff0c;虛擬操作系統基礎架構&#xff09;架構在桌面虛擬化領域具有其獨特的優勢&#xff0c;使得它在某些場景下表現尤為出色。以下是幾個具體場景&#xff1a; 1. 重載性能需求場景 表現&#xff1a; 高效利用…

聚類分析方法(二)

目錄 三、層次聚類方法&#xff08;一&#xff09;層次聚類策略&#xff08;二&#xff09;AGNES算法&#xff08;三&#xff09;DIANA算法 四、密度聚類方法&#xff08;一&#xff09;基本概念&#xff08;二&#xff09;算法描述&#xff08;三&#xff09;計算實例&#xf…

Google賬號輸入用戶名和密碼后提醒要到手機通知點是,還要點擊數字,但是我手機收不到

有一些朋友換了一個新的電腦后手機登錄谷歌賬號時&#xff0c;用戶名和密碼都正確輸入以后&#xff0c;第三步彈出一個提示&#xff0c;要在手機上的通知欄點擊是&#xff0c;并且點擊手機上相應的數字才能繼續登錄。 但是自己的手機上下拉通知欄卻沒有來自谷歌的通知&#xf…

ADOQuery 查詢MSSQL存儲過程一個莫名其妙的錯誤;

在 SSMS 中執行完成正常的的存儲過程。 也能正常的返回想要的數據&#xff0c;&#xff0c;然后通過 ADO 查詢時&#xff0c;總是提法 某 字段不存在的問題&#xff1b; 此問題困擾了一天。 例如&#xff08;當然&#xff0c;實際數據結構比下面舉例的復雜&#xff09;&…

C++八股(二)之C++11新特性

一、C++11有什么新特性?? 自動類型推導(Type Inference):引入了 auto 關鍵字,允許編譯器根據初始化表達式的類型自動推導變量的類型。統一的初始化語法(Uniform Initialization Syntax):引入了用花括號 {} 進行初始化的統一語法,可以用于初始化各種類型的對象,包括基…

符號同步、定時同步和載波同步

符號同步、定時同步和載波同步是通信系統中重要的同步技術&#xff0c;它們各自承擔著不同的功能和作用。以下是對這三種同步技術的詳細解釋&#xff1a; 符號同步 定義&#xff1a; 符號同步&#xff0c;也稱為定時恢復或時鐘恢復&#xff0c;是指在數字通信系統中&#xff…