Spring中的三級緩存和循環依賴

三級緩存

在 Spring 中,Bean 的創建過程涉及到三級緩存。這三級緩存分別是 singletonObjects、earlySingletonObjects 和 singletonFactories。它們在 Spring 容器啟動時用于存儲正在創建的 Bean 實例。

在 Spring 源碼中,三級緩存涉及到了 DefaultSingletonBeanRegistry 類。這個類是 Spring 容器中負責管理單例 Bean 的注冊表,其中包含了三級緩存的實現。下面是 DefaultSingletonBeanRegistry 中與三級緩存相關的源碼片段:

public abstract class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {// 一級緩存:singletonObjectsprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二級緩存:earlySingletonObjectsprivate final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// 三級緩存:singletonFactoriesprivate final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);...protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 從一級緩存中獲取 Bean 實例Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 從二級緩存中獲取 Bean 實例singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 從三級緩存中獲取 Bean 實例的 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 使用 ObjectFactory 創建 Bean 實例singletonObject = singletonFactory.getObject();// 將創建好的 Bean 實例放入二級緩存中this.earlySingletonObjects.put(beanName, singletonObject);// 從三級緩存中移除 ObjectFactorythis.singletonFactories.remove(beanName);}}}}return singletonObject;}...}

DefaultSingletonBeanRegistry 類中,singletonObjects 用于存儲已經完成初始化的 Bean 實例,earlySingletonObjects 用于存儲尚未完成初始化的 Bean 實例,singletonFactories 用于存儲創建 Bean 的工廠對象。在 getSingleton() 方法中,首先會嘗試從一級緩存 singletonObjects 中獲取 Bean 實例,如果找不到且 Bean 正在創建中,則會從二級緩存 earlySingletonObjects 中獲取 Bean 實例,如果仍然找不到且允許早期引用,則會從三級緩存 singletonFactories 中獲取 Bean 實例的工廠對象,并使用工廠對象創建 Bean 實例,然后將創建好的 Bean 實例放入二級緩存 earlySingletonObjects 中。

  1. singletonObjects:

    • 這是最常見的單例對象緩存。當容器創建 Bean 時,會首先嘗試從 singletonObjects 緩存中獲取已經創建好的 Bean 實例。
    • 如果能夠從 singletonObjects 中獲取到 Bean 實例,就直接返回該實例。
    • 如果 singletonObjects 緩存中不存在 Bean 實例,則繼續后續的創建流程。
  2. earlySingletonObjects:

    • 這個緩存用于存儲尚未完成初始化的早期單例對象。
    • 在創建 Bean 的過程中,如果發現 Bean 的初始化依賴其他 Bean,而這些依賴的 Bean 正好是單例的,則會暫時將正在創建的 Bean 實例放入 earlySingletonObjects 緩存中,以便解決循環依賴的問題。
    • 等到 Bean 的創建完成后,會將其移動到 singletonObjects 緩存中。
  3. singletonFactories:

    • 這個緩存用于存儲創建 Bean 的工廠對象(ObjectFactory)。
    • 當 Bean 的創建過程中需要解決循環依賴時,會將創建 Bean 的工廠對象放入 singletonFactories 緩存中。
    • 當需要獲取正在創建的 Bean 的依賴時,會從 singletonFactories 緩存中獲取對應的工廠對象,然后通過工廠對象創建 Bean 的代理對象,并將代理對象放入 earlySingletonObjects 緩存中,以便解決循環依賴的問題。

這三級緩存在 Spring 容器啟動時起到了至關重要的作用,它們協同工作以解決 Bean 的循環依賴問題,確保容器能夠正確地創建和管理 Bean 實例。


循環依賴

循環依賴是指兩個或多個 Bean 之間相互依賴形成的循環引用關系。在 Spring 中,循環依賴通常出現在以下場景中:

  1. 構造器注入循環依賴: 當兩個或多個 Bean 在它們的構造器中相互依賴時,就會出現構造器注入的循環依賴。例如,BeanA 的構造器參數依賴于 BeanB,而 BeanB 的構造器參數又依賴于 BeanA。

  2. setter 方法注入循環依賴: 當兩個或多個 Bean 在它們的 setter 方法中相互依賴時,就會出現 setter 方法注入的循環依賴。例如,BeanA 的某個屬性依賴于 BeanB,而 BeanB 的某個屬性又依賴于 BeanA。

為了解決循環依賴的問題,Spring 使用了三級緩存的機制。這個機制的原理如下:

  1. 當容器創建 Bean 的過程中,如果發現循環依賴,會將正在創建的 Bean 實例放入到早期單例對象的緩存中(即二級緩存 earlySingletonObjects)。

  2. 同時,為了解決循環依賴,會創建 Bean 的工廠對象(即 ObjectFactory),并將工廠對象放入到三級緩存 singletonFactories 中。

  3. 當需要解決循環依賴時,容器會從三級緩存 singletonFactories 中獲取 Bean 的工廠對象,并使用工廠對象創建 Bean 的代理對象。

  4. 創建好的代理對象會被放入到二級緩存 earlySingletonObjects 中,以便在后續的 Bean 創建過程中能夠獲取到已經創建的 Bean 的代理對象。

  5. 當所有 Bean 都創建完成后,容器會再次遍歷二級緩存 earlySingletonObjects 中的 Bean 實例,將它們初始化并放入一級緩存 singletonObjects 中。

通過三級緩存的機制,Spring 能夠解決循環依賴的問題,確保容器能夠正確地創建和管理 Bean 實例。這種機制下,即使存在循環依賴,也能夠保證所有 Bean 都能夠正確地初始化和注入依賴。

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

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

相關文章

python02 循環與容器

一、if的條件判斷 1-1 if elif else 判斷年齡屬于哪個年齡段 # 判斷學生 core input(請輸入成績) ? if int(core) >90 :print(優秀) elif int(core) >70 and int(core) <90:print(中等) elif int(core) >60 and int(core) <70:print(及格) else:print(不及…

20240521在Ubuntu20.04下編譯RK3588的IPC方案的編譯環境問題makeinfo: not found

20240521在Ubuntu20.04下編譯RK3588的IPC方案的編譯環境問題makeinfo: not found 2024/5/21 20:52 viewproviewpro-ThinkBook-16-G5-IRH:~/RK3588_IPC_SDK$ sudo apt-get install texinfo viewproviewpro-ThinkBook-16-G5-IRH:~$ viewproviewpro-ThinkBook-16-G5-IRH:~$ md5su…

【Basic】Linux Labs

文章目錄 前言一、Linux Labs二、知識點ssh介紹ssh的主要功能SSH的工作原理SSH的常見用法 解題感悟 前言 由于我參加了網絡安全的比賽(被迫)… but我毛都不會&#xff0c;所以我只能臨時抱佛腳… 順便把學習的過程記錄下來&#xff0c;歡迎收看小白0基礎ctf踩坑分享 一、Linux…

【正點原子Linux連載】 第四十六章 M.2硬盤驅動實驗摘自【正點原子】ATK-DLRK3568嵌入式Linux驅動開發指南

1&#xff09;實驗平臺&#xff1a;正點原子ATK-DLRK3568開發板 2&#xff09;平臺購買地址&#xff1a;https://detail.tmall.com/item.htm?id731866264428 3&#xff09;全套實驗源碼手冊視頻下載地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第四十…

【selenium】自動化測試chrome webdriver驅動下載網址,V123版本以上

Hi&#xff0c;大家好&#xff0c;今天和大家分享下最新的selenium自動化測試&#xff0c;chrome瀏覽器驅動下載的最新地址 chrome webdriver下載網址&#xff0c;適用于瀏覽器版本V123以上

結構型模式 (Python版)

代理模式 from abc import ABC, abstractmethod# 買的行為&#xff08;抽象類&#xff09; class Buy(ABC):abstractmethoddef buy_ticket(self):pass# 男人&#xff08;具體類&#xff09; class Man(Buy):# 男人買票def buy_ticket(self):print("Man 買票成功&#xff…

【輸入示例100,999 輸出示例4】水仙花數

// “水仙花數”是指一個三位正整數&#xff0c;其各位上的數字的立方和等于該數本身。如:1^35^33^3153&#xff0c;因此153是一個水仙花數。輸入兩個三位正整數a和b(其中a<b)&#xff0c;求[a,b]范圍內水仙花數的個數。 //輸入示例100,999 //輸出示例4 #include <stdio.…

AI爆文寫作:如果你有一篇文章爆了,正確的做法是:自己抄襲自己,重復發,還可以繼續爆!

爆款總是相似的&#xff0c;如果你有一篇文章爆了&#xff0c;正確的做法&#xff0c;就是重復發&#xff0c;讓它繼續爆下去。 以前我在小紅書看到一個人&#xff0c;將一篇自己火的筆記&#xff0c;連續發了5次&#xff0c;每次點贊數據都不錯。 公眾號文章也是一樣的。 我…

Gin與OpenAPI(Swagger)的使用

一、背景 1、swagger與openapi Swagger&#xff1a; 一種用于描述RESTFUL API的規范&#xff0c;它提供了一種簡單的來描述API的請求和相應參數、錯誤碼、返回數據類型等信息&#xff0c;是開發者可以方便了解API使用方式。 官網: https://swagger.io/ OpenAPI : 始于 …

gazebo仿真不起飛——QGC地面站查看下是否參數正確

檢查方法&#xff1a;打開QGC地面站查看是否能夠切入定點模式&#xff0c;不能的話查看定位數據來源參數

uniapp(微信小程序)退出小程序方法

一、描述 場景是&#xff1a;當用戶不予授權的時候&#xff0c;不允許使用該小程序&#xff0c;在用戶點擊取消之后&#xff0c;應該關閉當前小程序&#xff0c;不讓他繼續使用。 二、代碼 uni.exitMiniProgram({success: function() {console.log(退出小程序成功);},fail: …

鴻蒙HarmonyOS實戰-Stage模型(信息傳遞載體Want)

&#x1f680;前言 應用中的信息傳遞是為了實現各種功能和交互。信息傳遞可以幫助用戶和應用之間進行有效的溝通和交流。通過信息傳遞&#xff0c;應用可以向用戶傳遞重要的消息、通知和提示&#xff0c;以提供及時的反饋和指導。同時&#xff0c;用戶也可以通過信息傳遞向應用…

FPGA 第4章 攝像頭Bayer轉rgb

參考文獻 彩色MT9V034攝像頭 Bayer轉rgb FPGA實現 https://www.cnblogs.com/hqz68/p/10413896.html 文章目錄 前言Bayer轉rgb算法解析 總結 前言 Bayer格式是相機內部的原始數據, 一般后綴名為.raw。 對于彩色圖像,一般是三原色數據&#xff0c;rgb格式。但是攝像頭一個像素…

【linux-IMX6ULL-LED字符驅動框架完善】

目錄 1.簡介&#xff12;.前置知識2.1 重要函數及結構體2.2 程序框架流程 3. 代碼詳解&#xff1a; 1.簡介 在上節&#xff0c;我對linux-IMX6ULL-字符設備驅動簡單框架實驗進行了說明和構建&#xff0c;但是也存在幾個問題&#xff1b; 需要手動指定設備號&#xff0c;不能自…

TCP 與 UDP

0. tcp 與 udp 的 異同特性 TCPUDPname傳輸控制協議用戶數據報協議面向連接&#xff1f; 需要 傳輸數據前建立連接傳輸完畢后斷開連接不需要可靠的傳輸數據&#xff1f; 可靠 有確認機制&#xff08;三次握手&#xff09; 有確認、窗口、重傳、擁塞控制的機制保證數據可靠傳輸…

itertools拼裝迭代器

itertools拼裝迭代器 連接多個迭代器 內置的itertools模塊有一些函數可以把多個迭代器連城一個使用。 chain chain可以把多個迭代器從頭到尾連成一個迭代器。 import itertoolsit itertools.chain([1, 2, 3], [4, 5, 6]) print(list(it))>>> [1, 2, 3, 4, 5, 6]…

操作視頻號小店,新手最關心的問題,一篇給你講解清楚!

大家好&#xff0c;我是電商小V 新手去做視頻號小店的時候&#xff0c;心里面一定是有很多疑問的&#xff0c;會反復咨詢一些最關心的問題&#xff0c;因為他們要做好準備&#xff0c;以防后續做店過程中出現問題&#xff0c;其實新手關心的問題就那幾個&#xff0c;咱們今天就…

C++貪心算法3

過河的最短時間 #include<bits/stdc.h> using namespace std; void f(int); int n; int main() {system("color 1");cin>>n;int a[10010];for(int i0;i<n;i){cin>>a[i];}sort(a0,an);int ta[1];int k1n-2;int k2n-1;while(true){int t1a[0]a[k…

springboot2+mybatis-plus+vue3創建入門小項目[學生管理系統]02[實戰篇]

創建一個 vue 項目 創建這個新的文件夾 創建前端項目 eggbox 數據庫 SQL CREATE DATABASE IF NOT EXISTS egg DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; USE egg;CREATE TABLE stu (id INT AUTO_INCREMENT, -- 自增主鍵name VARCHAR(64) NOT NULL, -- 非空姓名字段&a…

前端傳參的三種方式

1、params 傳參 參數拼接在地址 url 的后面給后臺&#xff1b;地址欄中可見 案例1 地址欄&#xff1a;https://xxxxxxxx/admin/clues/detail?id558 接口代碼&#xff1a; export function getClueDetail(query: any) {return request<clueItem>({url: /clues/detai…