精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

解析Spring中的循環依賴問題:再探三級緩存(AOP)

開發 前端
當涉及Spring框架中動態代理的實現機制時,除了已經提到的earlySingletonObjects和singletonFactories這兩個緩存外,還有一個重要的緩存值得一提,那就是earlyProxyReferences。這個緩存的作用在于記錄某個原始對象是否已經進行過AOP(面向切面編程)處理。

前言

在之前的內容中,我們簡要探討了循環依賴,并指出僅通過引入二級緩存即可解決此問題。然而,你可能會好奇為何在Spring框架中還需要引入三級緩存singletonFactories。在前述總結中,我已經提供了答案,即AOP代理對象。接下來,我們將深入探討這一話題。

AOP

在Spring框架中,AOP的實現是通過一個名為BeanPostProcessor的類完成的,其中一個關鍵的BeanPostProcessor就是AnnotationAwareAspectJAutoProxyCreator。值得一提的是,該類的父類是AbstractAutoProxyCreator。在Spring的AOP機制中,通常會使用JDK動態代理或者CGLib動態代理來實現代理對象的生成。因此,如果在某個類的方法上設置了切面,那么最終這個類將需要生成一個代理對象來應用AOP的功能。

一般的執行流程通常是這樣的:A類--->生成一個普通對象-->屬性注入-->基于切面生成一個代理對象-->將該代理對象存入singletonObjects單例池中。

而AOP可以說是Spring框架中除了IOC之外的另一個重要功能,而循環依賴則屬于IOC的范疇。因此,為了讓這兩個重要功能同時存在于Spring框架中,Spring需要進行特殊處理。

三級緩存

在處理這種情況時,Spring框架利用了第三級緩存singletonFactories。下面我們來看一下關于三級緩存的源代碼實現:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    // Consistent creation of early reference within full singleton lock
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }

首先,singletonFactories中存儲的是某個beanName對應的ObjectFactory。在bean的生命周期中,生成完原始對象之后,Spring框架會構造一個ObjectFactory并將其存入singletonFactories中。這個ObjectFactory是一個函數式接口,因此支持Lambda表達式,形式為() -> getEarlyBeanReference(beanName, mbd, bean)。為了更清晰地理解這個過程,我提供一張圖片。

圖片圖片

getEarlyBeanReference

在上述Lambda表達式中,它實際上代表了一個ObjectFactory,執行該Lambda表達式將會調用getEarlyBeanReference方法。下面是getEarlyBeanReference方法的實現:

//AbstractAutowireCapableBeanFactory
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
            exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
        }
    }
    return exposedObject;
}

在整個Spring框架中,值得注意的是,只有AbstractAutoProxyCreator這個類在實現getEarlyBeanReference方法時才具有真正的意義。這個類專門用于處理AOP(面向切面編程)。

// AbstractAutoProxyCreator
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
 Object cacheKey = getCacheKey(bean.getClass(), beanName);
 this.earlyProxyReferences.put(cacheKey, bean);
 return wrapIfNecessary(bean, beanName, cacheKey);
}

那么,getEarlyBeanReference方法的具體操作是什么呢? 首先,它會獲取一個cachekey,這個cachekey實際上就是beanName。 接著,它會將beanName和bean(即原始對象)存儲到earlyProxyReferences中。 接下來,它會調用wrapIfNecessary方法進行AOP操作,這將生成一個代理對象。

那么,什么時候會調用getEarlyBeanReference方法呢?讓我們再次回到循環依賴的場景中。

圖片圖片

image

在我上一節的基礎上,我增加了兩句話,以便更好地理解觸發緩存機制以解決AOP代理對象生成的時機。

一旦原始對象通過構造方法生成后,會被存儲到三級緩存中,并且會與一個lambda表達式關聯。然而,在這個階段,它并不會被執行。

一旦BBean需要ABean時,系統會首先查看三級緩存以確定是否存在緩存。如果存在緩存,則lambda表達式將會被執行,其代碼已在前面展示過。該lambda表達式的目的是將代理對象放入earlySingletonObjects中。需要注意的是,此時代理對象并未被放入singletonObjects中。那么代理對象何時會被放入singletonObjects中呢?

這個時候你可能已經明白了earlySingletonObjects的用途。由于只獲取了A原始對象的代理對象,這個代理對象并不完整,因為A原始對象尚未進行屬性填充。因此,在這種情況下,我們不能直接將A的代理對象放入singletonObjects中。因此,我們只能將代理對象放入earlySingletonObjects,這樣依次類推。

在Spring框架中,在循環依賴場景下,當Bean B創建完成后,Bean A繼續其生命周期。在Bean A完成屬性注入后,根據其自身邏輯進行AOP操作。此時,我們知道Bean A的原始對象已經經歷了AOP處理,因此對于Bean A本身而言,不需要再次進行AOP。那么,如何確定一個對象是否已經經歷了AOP呢?

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

沒錯,這個earlyProxyReferences確實提前緩存了對象是否已經被代理過,這樣就避免了重復的AOP處理。

舉例反證

那么問題來了,當A對象創建時,它可以是原始對象,但當B對象創建時,卻成功創建了A的代理對象。然后再回頭給A對象進行屬性注入和初始化,這些操作似乎與代理對象無關?

這個問題涉及到了 Spring 中動態代理的實現。無論是使用cglib代理還是jdk動態代理生成的代理類,代理時都會將目標對象 target 保存在最終生成的代理 $proxy 中。你可以將代理對象看作是對原始對象地址的一層包裝,最終仍然會回到原始對象上。因此,對原始bean的進一步完善實際上也就是對代理對象的完善。

還有一個需要注意的問題,當A創建時,由于earlyProxyReferences緩存的原因,并沒有創建代理對象,因此此時A仍然保持為原始對象。我們知道,當bean創建完成后,它將被放入一級緩存中,但如果在此之后被其他對象引用,那不就會出現問題嗎?別人引用的都是原始對象了,而不是代理對象,但是請不要著急,因為在實例化之后,有一行代碼可以解決這個問題。

if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
......省略代碼

在實例化原始對象后,他會首先從三級緩存中檢查是否存在緩存對象。這是因為在創建B對象時,已經將A的代理對象放入二級緩存。因此,取出的對象是代理對象。接著,當進行 exposedObject == bean 的比較時,發現它們不相同。因此,以代理對象為準并將其返回。最終,最外層存儲的將是代理對象。

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

總結

在上一個章節中我們提到了今天要討論三級緩存,讓我們根據上面提到的三級緩存內容,做一個詳盡的總結:

  • singletonObjects:緩存經過了完整生命周期的bean。
  • earlySingletonObjects緩存了未經過完整生命周期的bean。當某個bean出現循環依賴時,該bean會被提前放入earlySingletonObjects中。如果該bean需要經過AOP,那么代理對象將會被放入earlySingletonObjects;否則,原始對象將被放入其中。然而,無論是代理對象還是原始對象,它們的生命周期都尚未完全結束。因此視為未經過完整生命周期的bean。
  • singletonFactories緩存的是一個ObjectFactory,這個ObjectFactory實際上是一個Lambda表達式。在每個Bean的生成過程中,當原始對象實例化完成后,會提前基于原始對象生成一個Lambda表達式,并將其保存到三級緩存中。這個Lambda表達式可能會被使用,也可能不會。如果當前Bean不存在循環依賴,那么這個Lambda表達式將不會被使用,當前的Bean將按照正常的生命周期執行完畢,并將自身放入singletonObjects中。但是,如果在依賴注入的過程中發現了循環依賴(即當前正在創建的Bean被其他Bean所依賴),則會從三級緩存中取出Lambda表達式,并執行它以獲取一個對象,然后將得到的對象放入二級緩存中。需要特別注意的是,如果當前Bean需要AOP處理,則執行Lambda表達式后得到的將是代理對象;否則,直接得到的是原始對象。

當涉及Spring框架中動態代理的實現機制時,除了已經提到的earlySingletonObjects和singletonFactories這兩個緩存外,還有一個重要的緩存值得一提,那就是earlyProxyReferences。這個緩存的作用在于記錄某個原始對象是否已經進行過AOP(面向切面編程)處理。

至此,整個循環依賴解決完畢。

責任編輯:武曉燕 來源: 靈墨AI探索室
相關推薦

2023-12-12 17:44:13

三級緩存Bean

2022-05-08 19:23:28

Spring循環依賴

2023-02-26 11:15:42

緩存循環依賴

2024-12-20 16:46:22

Spring三級緩存

2025-06-26 01:55:00

2022-03-01 18:03:06

Spring緩存循環依賴

2022-12-02 12:01:30

Spring緩存生命周期

2021-01-29 14:14:47

動態代理緩存

2024-04-15 08:17:21

Spring依賴注入循環依賴

2024-04-12 07:51:05

SpringBean初始化

2025-07-02 03:10:00

2021-05-06 07:58:57

Spring BeanIOCAOP

2023-05-04 08:06:27

Spring循環依賴

2024-03-18 00:00:00

SpringBean設計

2021-06-27 21:06:47

開發循環依賴

2019-11-26 14:30:20

Spring循環依賴Java

2020-02-06 13:40:35

編程緩存優化

2022-01-12 07:48:19

緩存Spring 循環

2009-06-12 09:00:15

Linux域名訪問

2025-10-27 00:00:00

Spring循環依賴分層
點贊
收藏

51CTO技術棧公眾號

亚洲精品久久久中文字幕| 欧美日韩亚洲在线| 精品无码久久久久久久久| 久久夜色精品国产噜噜av小说| 黑人狂躁日本妞一区二区三区| 日本精品一区二区| 精品国产无码AV| 奶水喷射视频一区| 久久国产精彩视频| 无码人妻精品一区二区三区温州| 韩日精品一区| 亚洲va韩国va欧美va精品 | 欧美一级免费片| 青青草原综合久久大伊人精品优势| 美女国内精品自产拍在线播放| 国产网站无遮挡| 中文成人激情娱乐网| 狠狠躁夜夜躁人人爽天天天天97| 在线观看一区二区三区三州| 天天干天天爽天天操| 精品一区二区在线免费观看| 欧美亚洲激情在线| 精品无码一区二区三区电影桃花 | 日韩在线免费视频观看| 国产情侣久久久久aⅴ免费| 黑人一区二区三区| 色婷婷久久久久swag精品 | www.综合网.com| 国产精品理伦片| 久久久水蜜桃| 欧美自拍偷拍一区二区| 韩国av一区二区三区在线观看| 青青草国产精品一区二区| 欧美成人精品欧美一级| 波多野结衣在线观看一区二区| 亚洲激情视频在线| 国产av一区二区三区传媒| 亚洲欧美久久精品| 欧美三级午夜理伦三级中视频| 日韩av中文字幕第一页| 图片区小说区亚洲| 尤物av一区二区| 一级性生活视频| 黄色免费在线看| 国产精品伦一区二区三级视频| 欧美亚洲国产免费| 色窝窝无码一区二区三区| 国产精品亚洲专一区二区三区| 国产日产亚洲精品| 中文天堂在线资源| 奇米色一区二区| 国产精品日日做人人爱| 日韩久久久久久久久久| 石原莉奈在线亚洲三区| 国产国语刺激对白av不卡| 日韩免费视频一区二区视频在线观看| 激情综合网址| 国内久久久精品| a v视频在线观看| 国产日韩视频| 国产成人精品日本亚洲专区61| 高清乱码免费看污| 久久天天综合| 国产精品久久久久久亚洲调教| 成人免费视频国产免费| 免费精品视频在线| 成人妇女淫片aaaa视频| 国产精品久久久久精| 国产剧情一区在线| 成人免费在线一区二区三区| 免费观看黄一级视频| 99久久精品费精品国产一区二区| 快播日韩欧美| 国产黄色片在线播放| 国产精品久久久久久久裸模| 欧美性视频在线播放| gogo在线观看| 精品久久久久久久久国产字幕| 亚洲熟妇无码另类久久久| 在线免费日韩片| 欧美四级电影网| 日韩不卡的av| 四虎884aa成人精品最新| 亚洲最新视频在线| 久久久久亚洲AV成人| 欧美久色视频| 日本国产高清不卡| 国产在成人精品线拍偷自揄拍| 国产成人自拍网| 精品一区2区三区| av在线之家电影网站| 亚洲精品乱码久久久久久久久| 91网站在线观看免费| 成人性生交大片免费网站| 欧美日韩免费高清一区色橹橹 | 欧美wwwwww| 中文字幕久久精品| 久久综合久久鬼| 日韩1区2区日韩1区2区| 国产99在线免费| 成年人免费在线视频| 有码一区二区三区| 午夜视频在线瓜伦| 6080亚洲理论片在线观看| 亚洲欧美激情四射在线日| 色婷婷在线视频观看| 西西人体一区二区| 1卡2卡3卡精品视频| 国产区av在线| 亚洲午夜久久久久久久久电影网 | 国产日产欧美视频| 精品视频在线播放一区二区三区| 日韩精品视频三区| 久草视频手机在线观看| 免费精品视频在线| 欧美一区免费视频| 高清在线视频不卡| 91精品国产色综合久久| 久久丫精品忘忧草西安产品| 激情综合电影网| 91在线免费网站| 国产69久久| 日韩欧美中文字幕在线播放| 中文字幕一区二区三区人妻在线视频| 精品日韩欧美一区| 欧美在线激情网| 欧美一区二区黄片| 亚洲国产美女搞黄色| 国产一级片中文字幕| 91亚洲一区| 国产精品一区二区三区久久| 欧洲毛片在线| 狠狠躁天天躁日日躁欧美| zjzjzjzjzj亚洲女人| 最新国产精品久久久| 国产在线播放91| 五月天婷婷在线视频| 在线观看日韩av先锋影音电影院| 久久人人妻人人人人妻性色av| 欧美日本一区二区视频在线观看| 成人黄色在线观看| 瑟瑟视频在线| 欧美日韩一区久久| 美女网站视频色| 老司机午夜精品| 成年人黄色在线观看| 在线视频成人| 精品中文字幕乱| 亚洲AV无码精品色毛片浪潮| 亚洲欧美激情一区二区| 亚洲一区二区中文字幕在线观看| 欧美国产一级| 成人午夜两性视频| 中文字幕中文字幕在线中高清免费版| 4438成人网| 国产精品成人免费观看| 丁香五精品蜜臀久久久久99网站| 浴室偷拍美女洗澡456在线| 精品视频成人| 久久久人成影片一区二区三区| 狠狠综合久久av一区二区| 亚洲成人精品在线观看| 国产伦精品一区二区三区妓女| 久久国产精品99国产| 亚洲精品9999| 国产精品亚洲欧美日韩一区在线 | 日韩成人免费av| 久久香蕉频线观| www.色视频| 天天射综合影视| 最新中文字幕av| 国产在线精品一区二区不卡了 | 欧美激情视频一区二区三区| 日日av拍夜夜添久久免费| 深夜福利亚洲导航| www视频在线| 色婷婷综合久久久中文一区二区| 正在播放国产对白害羞| 999国产精品视频免费| 国产麻豆一精品一av一免费 | 美女脱光内衣内裤视频久久影院| 中文字幕一区二区三区乱码| 天堂va欧美ⅴa亚洲va一国产| 午夜免费日韩视频| 午夜视频在线| 亚洲丁香久久久| 欧美日韩a v| 一区二区三区精品在线| 无套内谢大学处破女www小说| 麻豆中文一区二区| 无码日本精品xxxxxxxxx| 精品一区欧美| 亚洲bt天天射| 日本成人三级电影| 欧美日韩xxxxx| 黄网站在线观看| 精品久久久久久久人人人人传媒 | 在线视频日本亚洲性| 99久久一区二区| 黑人欧美xxxx| 免费三片在线播放| 亚洲国产精品成人久久综合一区| 性猛交╳xxx乱大交| 免费不卡在线观看| 玩弄中年熟妇正在播放| 亚洲国产日韩欧美在线| 人偷久久久久久久偷女厕| 国产高清视频一区二区| 日本午夜在线亚洲.国产| av网站大全在线| 在线观看欧美日韩| 婷婷国产在线| 欧美tickling网站挠脚心| 亚洲综合成人av| 精品毛片网大全| 欧美三级免费看| 最新高清无码专区| 久久丫精品忘忧草西安产品| www.亚洲色图| 欧美一级大片免费看| 美女高潮久久久| 成熟老妇女视频| 一本久道久久综合婷婷鲸鱼| 欧美美女黄色网| 婷婷亚洲最大| 亚洲成人一区二区三区| 亚洲aa在线| 狠狠色噜噜狠狠狠狠色吗综合| 国产精品成人**免费视频| 国产精品视频免费在线| 91久久国产综合久久91猫猫| 欧美精品久久久久久久久久| 黄在线免费观看| 最近2019年中文视频免费在线观看 | 亚洲电影在线观看| 肥臀熟女一区二区三区| 91精品国产一区二区三区蜜臀| 在线免费看av的网站| 欧洲av一区二区嗯嗯嗯啊| 日本熟妇毛茸茸丰满| 一区二区三区中文字幕在线观看| 久久精品一区二区三区四区五区| 日本一区二区三区久久久久久久久不 | 久久在线观看视频| 黄网站在线免费看| 美女av一区二区| 91精品久久久久久粉嫩| 大量国产精品视频| www红色一片_亚洲成a人片在线观看_| 日韩中文字幕在线看| 日本综合在线| 成年无码av片在线| 男插女视频久久久| 久久久亚洲欧洲日产国码aⅴ| 精品精品导航| 国内偷自视频区视频综合| 妞干网免费在线视频| 欧美怡红院视频一区二区三区| 麻豆理论在线观看| 日本一区二区三区在线播放| 欧美一区久久久| 国产精品久久久久av| 97人人做人人爽香蕉精品| 国产精品主播视频| 久久久国产精品入口麻豆| 91香蕉视频在线下载| 成人台湾亚洲精品一区二区| 国产美女精品久久久| 日韩精品免费一区二区三区竹菊| 免费国产一区二区| 久久蜜桃av| 国产成人一区二区三区别| 99精品视频免费全部在线| 能在线观看的av网站| 久久国产视频网| 中文字幕第六页| 91免费在线播放| 人妻互换一区二区激情偷拍| 亚洲欧美另类图片小说| 欧美福利视频一区二区| 亚洲无毛电影| 亚洲最大福利视频| 婷婷综合福利| 一本一本a久久| 亚洲日韩视频| 天天操,天天操| 成人免费视频一区| 亚洲一区二区自偷自拍| 亚洲人吸女人奶水| 日韩三级一区二区三区| 欧美午夜片在线看| 国产成人无码www免费视频播放| 亚洲欧美国产视频| 1769免费视频在线观看| 日本不卡视频在线播放| 韩国一区二区三区视频| 欧美18视频| 午夜国产精品视频| 手机在线看福利| 成人动漫中文字幕| 日韩激情小视频| 色综合久久88色综合天天6| 99精品视频在线播放免费| 亚洲美腿欧美激情另类| 欧美家庭影院| 91精品免费久久久久久久久| 日韩在线黄色| 欧美极品少妇无套实战| 国产亚洲精品久| 激情久久五月天| 又色又爽又黄18网站| 中文字幕欧美激情| 日本在线观看中文字幕| 51精品国自产在线| 国产高清自拍视频在线观看| 久久久人成影片一区二区三区| 欧美高清影院| 日本高清不卡三区| 制服诱惑一区二区| 亚洲精品乱码久久久久久蜜桃欧美| 中文字幕av一区二区三区免费看| 日韩伦理在线视频| 日韩欧美国产综合在线一区二区三区| 成年人视频在线看| 日韩**中文字幕毛片| 国产18无套直看片| 欧美电影一区| 久久国产精品视频在线观看| 国产一区二区三区日韩| 中文字幕伦理片| 色悠悠久久综合| 亚洲av成人精品一区二区三区在线播放| 久久视频国产精品免费视频在线| 浪潮色综合久久天堂| 精品国产免费人成电影在线观...| 欧美伊人影院| 亚洲第一成肉网| 中文字幕日韩一区| 中文字幕在线观看国产| 一区二区三区动漫| 国产精品久久久久av电视剧| 免费在线观看91| 午夜亚洲精品| 香蕉视频久久久| 日韩欧美国产激情| 美女扒开腿免费视频| 99久久精品情趣| 日本在线视频免费| 亚洲电影在线看| 日韩av一卡| 日韩精品一区二区三区丰满 | 国产欧美精品一区aⅴ影院 | 波多野在线观看| 国产偷国产偷亚洲高清97cao| 一区在线视频观看| 黄色av网址在线观看| 欧美日韩激情小视频| 香蕉国产在线视频| 日韩免费不卡av| 成人免费在线播放| 亚洲日本黄色片| 一区二区三区四区蜜桃| 欧美 日韩 人妻 高清 中文| 国内成人精品一区| 一区二区小说| 免费看污黄网站| 自拍偷拍国产精品| 亚洲欧美另类综合| 57pao精品| 成人av国产| 亚洲一区二区三区四区精品| 亚洲综合在线五月| 色婷婷中文字幕| 国产精品黄视频| 欧美精选在线| 在线免费看黄视频| 欧美久久一区二区| 福利网站在线观看| 欧美日韩精品免费观看| 麻豆成人综合网| 国产亚洲第一页| 亚洲人永久免费| 日韩第一区第二区| 国产精品亚洲αv天堂无码| 成人免费小视频| 色欲久久久天天天综合网| 国产精品福利在线观看| 中文av一区| 中文字幕免费高清| 日韩一级免费观看| 欧美亚洲韩国| 99er在线视频| 亚洲国产精品国自产拍av| 懂色av蜜臀av粉嫩av分享吧| 国产精品91免费在线| 欧美精品九九| 成年人视频软件| 日韩电影视频免费| 久久三级中文| 日日碰狠狠躁久久躁婷婷|