Spring 動態代理時是如何解決循環依賴的?為什么要使用三級緩存?

首先,我將簡單介紹一下Spring框架中的動態代理和循環依賴問題。

動態代理與循環依賴

1. 動態代理

在Spring框架中,動態代理是一種常用的技術,用于實現AOP(面向切面編程)。動態代理允許Spring在運行時為目標對象創建一個代理,以此來插入額外的邏輯,例如事務管理、日志記錄等。

2. 循環依賴

循環依賴是指兩個或多個Bean相互依賴,形成閉環,導致無法順利完成依賴注入。例如,Bean A依賴Bean B,而Bean B又依賴Bean A。

最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進大廠原來沒那么難。

這是大佬寫的,?7701頁的BAT大佬寫的刷題筆記,讓我offer拿到手軟

解決循環依賴:三級緩存

1. 三級緩存

Spring使用三級緩存解決循環依賴的問題:

  • 一級緩存:存放完全初始化完成的Bean(單例池)。
  • 二級緩存:存放原始Bean的早期引用。
  • 三級緩存:存放Bean的ObjectFactory,用于生成Bean的代理對象。

2. 工作機制

當Spring容器創建Bean時,首先將實例化后的原始Bean放入三級緩存。如果在Bean的完全初始化之前需要引用該Bean,Spring會通過三級緩存中的ObjectFactory來創建Bean的代理對象,并將其提升到二級緩存中。這樣,即使在Bean還未完全初始化之前,也能通過代理對象來解決循環依賴的問題。

使用場景與性能優化

1. 使用場景

  • 事務管理:使用動態代理管理事務邊界。
  • 日志記錄:在方法執行前后添加日志記錄。
  • 安全性:在方法調用前進行權限檢查。

2. 性能優化

  • 減少代理創建:僅對關鍵服務進行代理,避免過度使用動態代理。
  • 懶加載:適當使用懶加載,延遲Bean的初始化。

代碼示例

讓我們通過一個簡單的例子來理解Spring的動態代理和循環依賴的處理:

// 服務接口
public interface UserService {void addUser(String username);
}// 實現類
public class UserServiceImpl implements UserService {@Autowiredprivate OrderService orderService; // 依賴OrderService@Overridepublic void addUser(String username) {System.out.println("Adding user: " + username);// ... 其他邏輯 ...}
}// 另一個服務
public class OrderService {@Autowiredprivate UserService userService; // 依賴UserServicepublic void createOrder(String username) {System.out.println("Creating order for: " + username);// ... 其他邏輯 ...}
}

在這個例子中,UserService?和?OrderService?互相依賴。Spring通過三級緩存機制,確保這種循環依賴不會導致問題。

Spring中三級緩存機制是如何工作的,特別是在解決循環依賴的情況下。

我會用一個稍微復雜點的例子來展示這一機制。

場景設定

假設我們有兩個組件,A?和?B,它們互相依賴。為了簡化示例,我們假設它們都是單例(Spring默認的作用域)。

@Component
public class A {@Autowiredprivate B b;public A() {System.out.println("A 創建");}// A的其他方法...
}@Component
public class B {@Autowiredprivate A a;public B() {System.out.println("B 創建");}// B的其他方法...
}

三級緩存的工作原理

實例化

當Spring容器啟動時,它會嘗試創建這些Bean。

首先,它創建了A的實例。在這個過程中,Spring發現A需要依賴B。

然后,它開始創建B的實例。同樣,在創建B時,發現B需要依賴A。

三級緩存介入

此時,A的實例已經被部分創建,并存放在三級緩存中。

當Spring為B創建依賴A時,它不會重新創建A的實例。相反,它會使用存在于三級緩存中的A的早期引用。

這個早期引用足以滿足B對A的依賴,從而允許B的創建過程繼續。

依賴注入與完成創建

一旦B被成功創建,Spring會完成對A的依賴注入。

這時,A和B都已經被完全創建,并存放在Spring的一級緩存(即單例池)中。

關鍵點

這個過程中的“早期引用”通常是通過使用ObjectFactory創建的代理對象。

三級緩存主要用于解決這種循環依賴的問題,同時也確保了Spring容器的線程安全。

注意事項

雖然三級緩存機制很強大,但它僅適用于單例作用域的Bean。

對于原型作用域的Bean,Spring不會嘗試解決循環依賴,這可能會導致BeanCurrentlyInCreationException異常。

推薦一個學習?Spring源碼分析?的專欄文章

  • 01、Spring源碼分析 - 01-DispatcherServlet注冊過程
  • 02、Spring源碼分析 - 02-Resource
  • 03、Spring源碼分析 - 03-ResourceLoader
  • 04、Spring源碼分析 - 04-類型轉換
  • 05、Spring源碼分析 - 05-字段格式化
  • 06、Spring源碼分析 - 06-ResolvableType
  • 07、Spring源碼分析 - 07-BeanWrapper
  • 08、Spring源碼分析 - 08-DataBinder
  • 09、Spring源碼分析 - 09-PropertySourcesPropertyResolver
  • 10、Spring源碼分析 - 10-Environment
  • 11、Spring源碼分析 - 11-BeanFactory的實現
  • 12、Spring源碼分析 - 12-BeanFactory創建Bean的重要流程圖
  • 13、Spring源碼分析 - 13-DispatcherServlet中WebApplicationContext啟動過程
  • 14、Spring源碼分析 - 14-Spring默認重要的組件
  • 15、Spring源碼分析 - 15-ConfigurationClassPostProcessor
  • 16、Spring源碼分析 - 16-AutowiredAnnotationBeanPostProcessor
  • 17、Spring源碼分析 - 17-RequiredAnnotationBeanPostProcessor
  • 18、Spring源碼分析 - 18-CommonAnnotationBeanPostProcessor
  • 19、Spring源碼分析 - 19-ConfigurationClassPostProcessor
  • 20、Spring源碼分析 - 20-Spring事件/監聽器機制
  • 21、Spring源碼分析 - 21-Spring AOP概述
  • 22、Spring源碼分析 - 22-Spring AOP的實現原理之ProxyFactoryBean
  • 23、Spring源碼分析 - 23-TargetSource目標源
  • 24、Spring源碼分析 - 24-基于注解@Aspect的AOP實現
  • 25、Spring源碼分析 - 25-Spring異步實現原理
  • 26、Spring源碼分析 - 26-TaskExecutor與TaskScheduler
  • 27、Spring源碼分析 - 27-基于注解@Scheduled定時任務實現
  • 28、Spring源碼分析 - 28-Spring緩存原理詳解
  • 29、Spring源碼分析 - 29-JdbcTemplat的設計與實現
  • 30、Spring源碼分析 - 30-Spring編程式事物的設計與實現
  • 31、Spring源碼分析 - 31-Spring聲明式事物的設計與實現
  • 32、Spring源碼分析 - 32-基于注解@Transactional的事物實現
  • 33、Spring源碼分析 - 32-基于注解@Transactional的事物實現
  • 34、Spring源碼分析 - 34-Spring Bean作用域的設計與實現
  • 35、Spring源碼分析 - 35-Spring MVC設計原理
  • 36、Spring源碼分析 - 36-Spring MVC參數值的綁定
  • 37、Spring源碼分析 - 37-Spring MVC的異常處理
  • 38、Spring源碼分析 - 38-RestTemplate詳解
  • 39、Spring源碼分析 - 39-Spring容器生命周期回調接口LifeCycle
  • 40、Spring源碼分析 - 40-Spring Validation參數校驗的使用與原理
  • 41、Spring源碼分析 - 41-ClassPathBeanDefinitionScanner
  • 42、Spring源碼分析 - 42-@Conditional詳解

真實案例比較

在實際開發中,我們通常會遇到以下幾種情況:

  1. 簡單的CRUD操作:通常不需要動態代理。
  2. 復雜的業務邏輯:涉及事務、安全性檢查時,動態代理非常有用。
  3. 高性能要求的場景:在這種場景下,過度使用動態代理

最后說一句(求關注,求贊,別白嫖我)

最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進大廠原來沒那么難。

這是大佬寫的, 7701頁的BAT大佬寫的刷題筆記,讓我offer拿到手軟

項目文檔&視頻:

項目文檔 & 視頻

本文,已收錄于,我的技術網站 ddkk.com,有大廠完整面經,工作技術,架構師成長之路,等經驗分享

求一鍵三連:點贊、分享、收藏

點贊對我真的非常重要!在線求贊,加個關注我會非常感激

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

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

相關文章

C++『異常』

?個人主頁: 北 海 🎉所屬專欄: C修行之路 🎃操作環境: Visual Studio 2022 版本 17.6.5 文章目錄 🌇前言🏙?正文1.異常基本概念1.1.C語言異常處理方式1.2.C異常處理方式 2.異常的使用2.1.異常…

在線網頁生成工具GrapesJS

項目地址 https://github.com/GrapesJS/grapesjshttps://github.com/GrapesJS/grapesjs 項目簡述 這是一個基于node.js的在線網頁生成項目,對簡化開發有很大的幫助。 主要使用的語言如下: 編輯頁面如下: 使用也很簡潔 具體可以看下項目。…

使用c++編程語言,將字符串中的數字全部替換成字符串:number

給定一個字符串 s,它包含小寫字母和數字字符,請編寫一個函數,將字符串中的字母字符保持不變,而將每個數字字符替換為number。 樣例輸入:a1b2c3 樣例輸出:anumberbnumbercnumber 代碼如下: #incl…

12. MySQL 鎖機制

目錄 概述 MylSAM引擎 InnoDB引擎 概述 鎖是計算機協調多個進程或線程并發訪問某一資源的機制(避免爭搶)。在數據庫中,除傳統的計算資源(如CPU、RAM、I/O等)的爭用以外,數據也是一種供許多用戶共享的資如何保證數據…

Pytest中使用Fixture替換Unittest的Setupclass及Pytest使用裝飾器應用參數化

1 類里使用Fixture Pytest中夾具(Fixture)有幾種生命周期:function->model->class->session->packages,其中默認為function。 import pytest from Common.logger import Log from Common.Operator import * fro…

C#中的Attributes特性創建和結合反射應用舉例

C#中的特性入門學習 Attributes官方介紹概述 Attributes provide a powerful method of associating metadata, or declarative information, with code (assemblies, types, methods, properties, and so forth). After an attribute is associated with a program entity, …

深入理解Vue.js中的this:解析this關鍵字及其使用場景

在Vue.js中,this 和 that 可能是指向不同對象的兩個變量,或者是在代碼中使用時的錯誤。 this: 在Vue組件中,this 指向當前組件的實例。可以通過 this 訪問組件的屬性和方法。 例如,在Vue組件的 data 屬性中定義了一…

2023年第十屆GIAC全球互聯網架構大會-核心PPT資料下載

一、峰會簡介 談到一個應用,我們首先考慮的是運行這個應用所需要的系統資源。其次,是關于應用自身的架構模式。最后,還需要從軟件工程的不同角度來考慮應用的設計、開發、部署、運維等。架構設計對應用有著深遠的影響,它的好壞決…

Leetcode659. 分割數組為連續子序列

Every day a Leetcode 題目來源:659. 分割數組為連續子序列 解法1:哈希 貪心 定義兩個哈希表: numsCount:統計數組 nums 中各元素出現次數。tailCount:存儲以數字 i 結尾的且符合題意的連續子序列個數。 算法&a…

極兔單號查詢,極兔快遞物流查詢,一鍵篩選出退回件

批量查詢極兔快遞單號的物流信息,一鍵篩選出其中的退回件。 所需工具: 一個【快遞批量查詢高手】軟件 極兔快遞單號若干 操作步驟: 步驟1:運行【快遞批量查詢高手】軟件,并登錄 步驟2:點擊主界面左上角的…

【Bootloader學習理解----跳轉優化異常】

筆者接著來介紹一下Bootloader的跳轉代碼以及優化 1、跳轉代碼理解 跳轉代碼可能要涉及到芯片架構的知識,要跳轉到對應的位置,還要設置相關的SP 堆棧指針,具體可以參考筆者這篇文章BootLoader的理解與實現。 STM32的跳轉代碼如下所示: u32 …

ClickHouse為何如此之快

針對ClickHose為什么很快的問題,基于對ClickHouse的基礎概念之上,一般會回答是因為是列式存儲數據庫,同時也會說是使用了向量化引擎,所以快。上面兩方面的解釋也都能夠站得住腳,但是依然不能夠解釋真正核心的原因。因為…

AI:101-基于深度學習的航空影像中建筑物識別

?? 本文選自專欄:人工智能領域200例教程專欄 從基礎到實踐,深入學習。無論你是初學者還是經驗豐富的老手,對于本專欄案例和項目實踐都有參考學習意義。 ??? 每一個案例都附帶有在本地跑過的核心代碼,詳細講解供大家學習,希望可以幫到大家。歡迎訂閱支持,正在不斷更新…

2023_刷題_二叉樹

文章目錄 書leixingleixing 書 leixing leixing

基于以太坊的智能合約開發Solidity(基礎篇)

參考教程:基于以太坊的智能合約開發教程【Solidity】_嗶哩嗶哩_bilibili 1、第一個程序——Helloworld: //聲明版本號(程序中的版本號要和編譯器版本號一致) pragma solidity ^0.5.17; //合約 contract HelloWorld {//合約屬性變…

Python軸承故障診斷 (四)基于EMD-CNN的故障分類

目錄 前言 1 經驗模態分解EMD的Python示例 2 軸承故障數據的預處理 2.1 導入數據 2.2 制作數據集和對應標簽 2.3 故障數據的EMD分解可視化 2.4 故障數據的EMD分解預處理 3 基于EMD-CNN的軸承故障診斷分類 3.1 訓練數據、測試數據分組,數據分batch 3.2 定義…

D : DS查找——折半查找求平方根

Description 假定輸入y是整數&#xff0c;我們用折半查找來找這個平方根。在從0到y之間必定有一個取值是y的平方根&#xff0c;如果我們查找的數x比y的平方根小&#xff0c;則x2<y&#xff0c;如果我們查找的數x比y的平方根大&#xff0c;則x2>y&#xff0c;我們可以據此…

stu05-前端的幾種常用開發工具

前端的開發工具有很多&#xff0c;可以說有幾十種&#xff0c;包括記事本都可以作為前端的開發工具。下面推薦的是常用的幾種前端開發工具。 1.DCloud HBuilder&#xff08;輕量級&#xff09; HBuilder是DCloud&#xff08;數字天堂&#xff09;推出的一款支持HTML5的web開發…

硬件開發筆記(十四):RK3568底板電路LVDS模塊、MIPI模塊電路分析、LVDS硬件接口、MIPI硬件接口詳解

若該文為原創文章&#xff0c;轉載請注明原文出處 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134634186 紅胖子網絡科技博文大全&#xff1a;開發技術集合&#xff08;包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬…

linux 關于$-的解釋(帖子搜索合集)

在學習Linux的時候&#xff0c;今天遇到了$-&#xff0c;什么意思呢&#xff1f;網上搜索了一些帖子&#xff1a; 帖子1&#xff1a; linux命令 $- 是什么意思 $- 是什么意思&#xff1f;有什么用&#xff1f;可以判斷什么交互式shell&#xff1f; $-記錄著當前設置的shell…