最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析Spring中的循環(huán)依賴問題

 更新時間:2023年11月14日 08:52:51   作者:荊軻刺秦  
這篇文章主要介紹了淺析Spring中的循環(huán)依賴問題,Spring 是利用了 三級緩存 來解決循環(huán)依賴的,其實現本質是通過提前暴露已經實例化但尚未初始化的 bean 來完成的,需要的朋友可以參考下

Spring的循環(huán)依賴

本文不會詳細講解 Spring 循環(huán)依賴的基礎問題。

我相信能閱讀到本文的,對 Spring 循環(huán)依賴已經有一定了解,但可能存在一些疑惑。本文就是嘗試來解決這些疑惑的。

我們都知道 Spring 是利用了 三級緩存 來解決循環(huán)依賴的,其實現本質是通過提前暴露已經實例化但尚未初始化的 bean 來完成的。

但是呢,我們仍然會想,這里為什么要使用三級緩存?而且,我相信,不少人都曾手寫過代碼來解決循環(huán)依賴的問題,那時候,他們也只用了二級緩存,參考下圖:

循環(huán)依賴二級緩存

我們可以仔細跟蹤序號,理清整個流程。所以,二級緩存是能夠解決循環(huán)依賴,這也符合它的本質:“提前暴露對象”。這個流程圖并沒有描述接下來的流程,這里使用文字簡單描述下:

  • 對象A獲取到已創(chuàng)建完成的對象B注入;
  • 對象A完成字段注入以及初始化,并放入一級緩存;
  • 對象A從二級緩存中移除;

既然二級緩存能夠解決循環(huán)依賴了,那為什么要使用三級緩存呢?網上的說法是,那是因為 Spring 中存在替換注入對象的問題。通俗地來說就是:“一個半成品對象有可能在被對象b注入以后,被更改為其它的實例對象,那么對象b注入的就是一個過期的對象了”。

這種情況會導致對象b注入了一個并不存在于容器中的對象A(因為被更改后的對象注入了容器,替換掉了原來的對象)。所以,大多數人會認為三級緩存是為了解決這個問題的,讓我們來看看真的是如此嘛?上代碼:

@Component
public class ServiceA {
    @Autowired
    private ServiceB serviceB;

}
@Component
public class ServiceB {
    @Autowired
    private ServiceA serviceA;

}
@Component
public class ResetServiceABeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("serviceA")){
            return new ServiceA();
        }
        return bean;
    }
}

ServiceA 和 ServiceB 互相依賴,ResetServiceABeanPostProcessor 則是為了在ServiceB 注入了原來的ServiceA 后,將原來的 ServiceA 給替換掉。我們模擬了上述場景,但最后的運行結果卻是得到了一個 BeanCurrentlyInCreationException 異常,異常在圖中的 620 行拋出。

異常拋出點

可以發(fā)現,似乎它并沒有解決這個“注入了過期對象”的問題,可是它至少檢測出了這個問題。所以,我個人認為,三級緩存并不是來解決這個問題,而是來在啟動時檢測這個問題的。

文章寫到這里似乎也差不多了,但我還想糾正一點,網上有很多對于三級緩存的描述如下:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	...
	// 從上至下 分表代表這“三級緩存”
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一級緩存
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二級緩存
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三級緩存
	...
	
	/** Names of beans that are currently in creation. */
	// 這個緩存也十分重要:它表示bean創(chuàng)建過程中都會在里面呆著~
	// 它在Bean開始創(chuàng)建時放值,創(chuàng)建完成時會將其移出~
	private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/** Names of beans that have already been created at least once. */
	// 當這個Bean被創(chuàng)建完成后,會標記為這個 注意:這里是set集合 不會重復
	// 至少被創(chuàng)建了一次的  都會放進這里~~~~
	private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
}

但源碼中的順序卻不是如此(我使用的是 5.1.5 版本):

	/** Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

但我想三級緩存的分層并不是依賴上面的源碼順序來分為一二三的,而應該是根據從緩存中獲取對象的順序來分層的:

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

最后,我結合上述的場景來分析下這三個“緩存”中元素的變化(省略了其它無關流程):

緩存變化

紅色線條代表取出元素,虛線代表最終將不存在。

這里做下總結:

二級緩存也是能解決循環(huán)依賴的,使用三級緩存是為了幫助檢測提前暴露的對象在后期被修改的這種情況;

通過 earlySingletonObjects 持有被暴露的對象,然后在最終返回對象時進行比對。如果不是同一個對象,則代表發(fā)生了對象后期被修改的情況。

到此這篇關于淺析Spring中的循環(huán)依賴問題的文章就介紹到這了,更多相關Spring的循環(huán)依賴內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • idea中@override報錯在實現接口方法時無法使用的解決

    idea中@override報錯在實現接口方法時無法使用的解決

    文章介紹了在使用IDEA新建Filter類時遇到的@Override注解報錯問題,原因是JDK版本過低,通過在maven配置文件中設置編譯插件或更改項目JDK版本,解決了該問題
    2025-12-12
  • 建議你使用LocalDateTime而不是Date哦

    建議你使用LocalDateTime而不是Date哦

    這篇文章主要介紹了建議你使用LocalDateTime而不是Date,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • Spring?AI?Alibaba框架構建智能體Agent的完整指南

    Spring?AI?Alibaba框架構建智能體Agent的完整指南

    隨著大語言模型(LLM)技術的快速發(fā)展,構建智能Agent應用變得越來越簡單,本文將通過兩個實際的代碼示例,展示如何使用Spring?AI?Alibaba框架構建功能豐富的天氣查詢Agent,感興趣的小伙伴可以了解下
    2026-03-03
  • Java實現的Excel列號數字與字母互相轉換功能

    Java實現的Excel列號數字與字母互相轉換功能

    這篇文章主要介紹了Java實現的Excel列號數字與字母互相轉換功能,涉及java針對Excel相關數值與字符串操作技巧,需要的朋友可以參考下
    2018-03-03
  • Java深入了解數據結構中常見的排序算法

    Java深入了解數據結構中常見的排序算法

    這篇文章主要介紹了Java常用的排序算法及代碼實現,在Java開發(fā)中,對排序的應用需要熟練的掌握,這樣才能夠確保Java學習時候能夠有扎實的基礎能力。那Java有哪些排序算法呢?本文小編就來詳細說說Java常見的排序算法,需要的朋友可以參考一下
    2022-01-01
  • Java 中間件Dubbo 服務降級以及Mock 機制詳解

    Java 中間件Dubbo 服務降級以及Mock 機制詳解

    本文將深入探討Dubbo的Mock機制,從原理、配置方式、使用場景到實戰(zhàn)案例,全面解析如何利用這一特性構建高可用的微服務系統(tǒng),感興趣的朋友跟隨小編一起看看吧
    2026-02-02
  • springboot中使用自定義兩級緩存的方法

    springboot中使用自定義兩級緩存的方法

    這篇文章主要介紹了springboot中使用自定義兩級緩存的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Spring源碼分析容器啟動流程

    Spring源碼分析容器啟動流程

    Spring的啟動流程可以歸納為三個步驟:初始化Spring容器,注冊內置的BeanPostProcessor的BeanDefinition到容器中、將配置類的BeanDefinition注冊到容器中、調用refresh()方法刷新容器
    2022-09-09
  • redisson特性及優(yōu)雅實現示例

    redisson特性及優(yōu)雅實現示例

    這篇文章主要為大家介紹了redisson特性及優(yōu)雅實現示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • 2021年最新Redis面試題匯總(1)

    2021年最新Redis面試題匯總(1)

    在程序員面試過程中redis相關的知識是常被問到的話題。這篇文章主要介紹了幾道Redis面試題,整理一下分享給大家,感興趣的小伙伴們可以參考一下
    2021-07-07

最新評論

镶黄旗| 宜丰县| 新田县| 惠安县| 共和县| 稻城县| 团风县| 广汉市| 白水县| 普兰县| 正阳县| 木兰县| 呼和浩特市| 海门市| 甘南县| 湖南省| 阿拉尔市| 鹤壁市| 鹿邑县| 梁山县| 台湾省| 南昌县| 湖北省| 安西县| 和政县| 丹凤县| 横山县| 乾安县| 焉耆| 卢湾区| 吴桥县| 游戏| 高平市| 大名县| 荥阳市| 洪洞县| 榕江县| 阜宁县| 二连浩特市| 介休市| 湖北省|