精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

六月天综合网| 精品在线91| 亚洲va欧美va人人爽午夜| 国产精品入口免费| 免费看污视频的网站| 香蕉视频官网在线观看日本一区二区| 日韩三级在线观看| 老熟妇仑乱视频一区二区| 久久日韩视频| 成人小视频免费观看| 国产成人一区二区三区电影| 国产精品白丝喷水在线观看| 蜜桃一区av| 欧美美女视频在线观看| 精品少妇一区二区三区在线| 生活片a∨在线观看| bt欧美亚洲午夜电影天堂| 国产精品久久久久久久久影视| 天天综合天天做| 国内精品久久久久久99蜜桃| 精品噜噜噜噜久久久久久久久试看| 奇米精品一区二区三区| 中文字幕免费高清电视剧网站在线观看 | 国产麻豆欧美日韩一区| 热re99久久精品国产66热| 粉嫩av性色av蜜臀av网站| 久久av网址| 亚洲福利视频网| 亚洲天堂一区二区在线观看| 88xx成人免费观看视频库| 亚洲狠狠爱一区二区三区| 中文字幕综合在线观看| 国产系列在线观看| www欧美成人18+| 国产成人精品日本亚洲11| 91亚洲欧美激情| 中文亚洲欧美| 97视频免费看| 国产性猛交普通话对白| 亚洲情侣在线| 精品国产一区二区三区久久久| 亚洲人人夜夜澡人人爽| 久久草在线视频| 精品国产成人在线影院| 中国男女全黄大片| 国产在线不卡一区二区三区| 欧美日韩免费一区二区三区 | 四虎4545www国产精品| 欧美日韩亚洲高清| 日本十八禁视频无遮挡| 91福利在线尤物| 亚洲午夜一区二区| 黄网站欧美内射| 黄视频在线免费看| 一区二区日韩av| 亚洲乱码日产精品bd在线观看| 精精国产xxxx视频在线| 国产精品久久福利| 熟妇熟女乱妇乱女网站| 成人a在线视频免费观看| 亚洲欧洲精品天堂一级| 成人手机视频在线| 新版中文在线官网| 亚洲香蕉伊在人在线观| 成人毛片一区二区| 欧美大片免费高清观看| 在线亚洲一区二区| 黄色成人免费看| 久久久精品一区二区毛片免费看| 一本大道久久a久久精品综合| 91免费视频网站在线观看| 中老年在线免费视频| 91国产成人在线| 亚洲欧洲日本精品| www.久久爱.com| 欧美tk—视频vk| 大乳护士喂奶hd| 亚洲色图丝袜| 最新日韩中文字幕| www青青草原| 亚洲麻豆一区| 日本久久91av| 6—12呦国产精品| 国产69精品久久99不卡| 你懂的视频在线一区二区| 国产高清免费av在线| 一区二区中文视频| 国产免费黄色一级片| 女生影院久久| 日韩一区二区三免费高清| 玖玖爱在线精品视频| 精品国产a一区二区三区v免费| 中文字幕免费精品一区高清| 欧美成人黄色网| 美女国产精品| 亚洲自拍欧美另类| 日本啊v在线| 最近日韩中文字幕| 日本少妇高潮喷水视频| 国产精品第一国产精品| 精品va天堂亚洲国产| 国产三级av在线播放| 国产精品videosex极品| 欧美一级黄色网| 国产伦精品一区二区三区视频痴汉| 不卡av电影在线播放| 一区二区三区四区视频在线| www.综合网.com| 欧美综合一区二区三区| 久久久高清视频| 国产精品成人a在线观看| 97精品视频在线播放| 91久久久久国产一区二区| 99v久久综合狠狠综合久久| 中文字幕欧美人与畜| 性欧美18xxxhd| 日韩无一区二区| 女人裸体性做爰全过| 亚洲一区视频| 国产精品日韩欧美一区二区| 免费在线看黄色| 欧美中文字幕久久| 亚洲一区二区在线免费| 欧美福利网址| 91精品一区二区| 国产精品一区二区三区四区色 | 波多野结衣午夜| www.视频一区| wwwwww欧美| 免费欧美网站| 久久久精品欧美| 精品无码一区二区三区的天堂| 波多野结衣一区二区三区 | 欧美一区=区| 国产精品久久亚洲7777| 91精品久久久久久粉嫩| 欧美乱妇20p| 大吊一区二区三区| 日本成人超碰在线观看| 欧美在线一区二区三区四区| 国产网站在线| 亚洲成人黄色在线| 日本熟妇色xxxxx日本免费看| 国产一区二区三区在线观看免费视频| 视频一区亚洲| 久久亚洲资源中文字| 在线播放国产一区中文字幕剧情欧美 | 在线观看日韩毛片| 国产免费看av| 日韩高清不卡一区二区三区| 欧美一二三四五区| 亚洲伦理影院| 中文字幕久热精品在线视频| 亚洲一二区视频| 中文字幕一区二区不卡| 中文字幕色网站| 亚洲一区二区三区无吗| 99精品国产高清在线观看| 午夜dj在线观看高清视频完整版| 欧美一区二区三区爱爱| 青草草在线视频| 成人久久18免费网站麻豆 | 欧美日韩视频免费观看| 国产一区二区三区三区在线观看 | 白浆在线视频| 亚洲精品网址在线观看| 成人黄色三级视频| 国产精品乱人伦| wwwxxx色| 国产一区91| 亚洲精品国产精品国自产| 久久久久久久性潮| 欧美丰满老妇厨房牲生活| 欧美熟妇乱码在线一区| 高跟丝袜欧美一区| youjizz亚洲女人| 国产一区二区不卡| 自慰无码一区二区三区| 精品久久中文| 亚洲综合大片69999| 9999精品成人免费毛片在线看| 亚洲精品视频中文字幕| 国产精品久久婷婷| 亚洲第一福利一区| 无码少妇精品一区二区免费动态| 精品一区二区免费视频| 国产免费黄色一级片| 日本一区二区在线看| 99porn视频在线| 巨茎人妖videos另类| 久久精品成人动漫| 天堂中文在线资源| 欧美精品三级在线观看| 日韩污视频在线观看| 欧美国产丝袜视频| 日本一区二区免费视频| 日韩精品一二三四| 久久视频免费在线| 国模吧精品视频| y111111国产精品久久婷婷| 成人香蕉视频| 欧美二区乱c黑人| 第九色区av在线| 亚洲国产精品成人一区二区| 中文在线资源天堂| 精品国产老师黑色丝袜高跟鞋| 在线观看天堂av| 91小视频在线观看| 初高中福利视频网站| 日韩精品三区四区| 亚洲熟妇国产熟妇肥婆| 欧美1区免费| 亚洲午夜精品久久| 亚洲专区视频| 国产麻豆一区二区三区在线观看| 日韩午夜视频在线| 国产成人精品久久久| heyzo一区| 久久成人国产精品| 亚洲搞黄视频| 亚洲亚裔videos黑人hd| 少妇高潮久久久| 欧美成人一区二区| 国产乱码一区二区| 欧美日韩久久一区二区| 午夜精品一区二| 欧美日韩午夜激情| www欧美在线| 亚洲午夜一区二区| 久久综合激情网| 一区二区三区四区av| 国产高清视频免费在线观看| 国产欧美一区二区精品性| 人妻无码中文久久久久专区| 国产成人av电影在线| 免费成年人高清视频| 久久99精品一区二区三区| 天堂中文视频在线| 久久看片网站| 日韩一级在线免费观看| 久久99伊人| 男人天堂999| 性欧美xxxx大乳国产app| 欧美成人一区二区在线观看| 99亚洲伊人久久精品影院红桃| 日本精品福利视频| 欧美日韩国产亚洲一区| 91社在线播放| 中文视频一区| 日韩欧美视频免费在线观看| 欧美日韩一卡| 美脚丝袜脚交一区二区| 1000部精品久久久久久久久| 激情伊人五月天| 欧美亚洲专区| 亚洲色图38p| 久久成人免费网| 一级黄色免费毛片| 懂色av一区二区三区免费看| 久久国产免费视频| 99精品视频一区二区| 青青草视频成人| 国产日韩精品视频一区| 日韩av毛片在线观看| 日韩毛片视频在线看| 久久久99精品| 五月天中文字幕一区二区| 欧美a∨亚洲欧美亚洲| 91国产视频在线观看| 97超碰国产在线| 日韩精品在线看片z| 天天综合网天天综合| 国产亚洲欧美日韩美女| 麻豆传媒在线免费看| 久久久久久国产免费| 亚洲色图官网| 国产欧美日韩精品丝袜高跟鞋| 精品视频在线播放一区二区三区| 国产精品手机在线| 美女毛片一区二区三区四区最新中文字幕亚洲 | 欧美疯狂做受xxxx高潮| 日本а中文在线天堂| 国产精品爽黄69天堂a| 视频欧美一区| 欧美日韩在线观看一区二区三区| 手机在线一区二区三区| 和岳每晚弄的高潮嗷嗷叫视频| 午夜在线视频一区二区区别| 岛国av在线免费| 99国产精品99久久久久久| 国产精品视频看看| 婷婷成人综合网| 国产精品久久久久久在线| 亚洲精品国产精品乱码不99按摩| jizz在线观看中文| 欧美激情性做爰免费视频| 99久久久国产精品免费调教网站| 97免费高清电视剧观看| 免费欧美一区| 欧美中日韩在线| 捆绑调教一区二区三区| 国产乱了高清露脸对白| 中文字幕五月欧美| 男女啊啊啊视频| 欧美一区二区精品久久911| 欧美日韩激情视频一区二区三区| 久久艳片www.17c.com| 希岛爱理一区二区三区av高清| **亚洲第一综合导航网站| 欧美丝袜激情| 日韩国产一级片| 国产一区 二区 三区一级| 亚洲成人黄色av| 午夜精品久久久久久久久| 91国偷自产中文字幕久久| 亚洲男人天堂久| 丁香花电影在线观看完整版| 91久久久久久久久久| 精品免费视频| 少妇性饥渴无码a区免费| 国产成人福利片| 精品人妻伦九区久久aaa片| 欧美亚一区二区| 三级无遮挡在线观看| 久久久女女女女999久久| 国产精品一区二区三区www| 水蜜桃一区二区| 久久精品人人| 亚洲av无码国产精品久久| 欧美日韩国产色| 黄片毛片在线看| 色综合男人天堂| 日本一区二区三区电影免费观看| 一区二区不卡在线视频 午夜欧美不卡'| 国产欧美日韩亚洲一区二区三区| 性农村xxxxx小树林| 一区二区三区波多野结衣在线观看 | 日韩一区和二区| 黄av在线免费观看| 国产一区二区在线免费| 99久久视频| 特级西西444www| 亚洲免费在线看| 国产视频在线一区| 久久高清视频免费| 日韩成人精品| 女人被男人躁得好爽免费视频 | 91精品人妻一区二区三区| 欧美日韩在线视频一区| 四虎精品成人影院观看地址| 国产综合在线看| 私拍精品福利视频在线一区| 激情五月宗合网| 久久久久久一二三区| 中文字幕一区二区三区四区欧美| 亚洲天堂久久av| 国产精品第一| 丰满人妻一区二区三区53号| 国产精品 欧美精品| 懂色av.com| 精品一区二区三区四区在线| 高清不卡亚洲| 亚洲欧洲精品一区| 国产一区二区h| 日韩 欧美 综合| 国产一区二区三区视频| 成人乱码手机视频| 黄色三级中文字幕| 久久蜜桃av一区二区天堂| a片在线免费观看| 久久亚洲成人精品| 精品一区二区男人吃奶| 干日本少妇首页| 中文字幕一区二区三区乱码在线| 亚洲av无码国产精品永久一区 | 99视频一区二区| 无码人妻精品一区二区50| 久久精品国产99国产精品澳门| 日韩欧美中文字幕在线视频| 国产免费黄视频| 国产精品国产三级国产普通话三级 | 精精国产xxxx视频在线播放| 欧美污视频久久久| 国产美女精品在线| 日本一区二区三区四区五区| 亚洲色图校园春色| 日韩av综合| 一区二区xxx| 亚洲国产美女搞黄色| 成年人在线视频| 国产精品免费一区二区三区| 日韩中文字幕91| 久久久精品视频免费| 在线日韩av观看| 久久超级碰碰| 亚洲va在线va天堂va偷拍| 都市激情亚洲色图| jizzjizz亚洲| 日韩在线第一区| 成人av电影免费观看|