亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于Spring中的三級(jí)緩存解析

 更新時(shí)間:2022年08月16日 14:42:35   作者:愛思考的實(shí)踐者  
這篇文章主要介紹了關(guān)于Spring中的三級(jí)緩存,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Spring的三級(jí)緩存

Spring三級(jí)緩存是為了解決對(duì)象間的循環(huán)依賴問題。

A依賴B,B依賴A,這就是一個(gè)簡(jiǎn)單的循環(huán)依賴。

我們來先看看三級(jí)緩存的源碼。

(1)查看“獲取Bean”的源碼,注意getSingleton()方法。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
? ? ? ? //第1級(jí)緩存 用于存放 已經(jīng)屬性賦值、完成初始化的 單列BEAN
? ? ? ? private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
? ? ? ? //第2級(jí)緩存 用于存在已經(jīng)實(shí)例化,還未做代理屬性賦值操作的 單例BEAN
? ? ? ? private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
? ? ? ? //第3級(jí)緩存 存儲(chǔ)創(chuàng)建單例BEAN的工廠
? ? ? ? private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
? ? ? ? //已經(jīng)注冊(cè)的單例池里的beanName
? ? ? ? private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
? ? ? ? //正在創(chuàng)建中的beanName集合
? ? ? ? private final Set<String> singletonsCurrentlyInCreation =
? ? ? ? ? ? ? ? Collections.newSetFromMap(new ConcurrentHashMap<>(16));
? ? ? ? //緩存查找bean ?如果第1級(jí)緩存沒有,那么從第2級(jí)緩存獲取。如果第2級(jí)緩存也沒有,那么從第3級(jí)緩存創(chuàng)建,并放入第2級(jí)緩存。
? ? ? ? protected Object getSingleton(String beanName, boolean allowEarlyReference) {
? ? ? ? ? ? Object singletonObject = this.singletonObjects.get(beanName); //第1級(jí)
? ? ? ? ? ? if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
? ? ? ? ? ? ? ? synchronized (this.singletonObjects) {
? ? ? ? ? ? ? ? ? ? singletonObject = this.earlySingletonObjects.get(beanName); //第2級(jí)
? ? ? ? ? ? ? ? ? ? if (singletonObject == null && allowEarlyReference) {
? ? ? ? ? ? ? ? ? ? ? ? //第3級(jí)緩存 ?在doCreateBean中創(chuàng)建了bean的實(shí)例后,封裝ObjectFactory放入緩存的bean實(shí)例
? ? ? ? ? ? ? ? ? ? ? ? ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
? ? ? ? ? ? ? ? ? ? ? ? if (singletonFactory != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //創(chuàng)建未賦值的bean
? ? ? ? ? ? ? ? ? ? ? ? ? ? singletonObject = singletonFactory.getObject();
? ? ? ? ? ? ? ? ? ? ? ? ? ? //放入到第2級(jí)緩存
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.earlySingletonObjects.put(beanName, singletonObject);
? ? ? ? ? ? ? ? ? ? ? ? ? ? //從第3級(jí)緩存刪除
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.singletonFactories.remove(beanName);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return singletonObject;
? ? ? ? } ??
? ? }

(2)“添加到第1級(jí)緩存”的源碼:

?protected void addSingleton(String beanName, Object singletonObject) {
? ? ? ? ? ? synchronized (this.singletonObjects) {
? ? ? ? ? ? ? ? // 放入第1級(jí)緩存
? ? ? ? ? ? ? ? this.singletonObjects.put(beanName, singletonObject);
? ? ? ? ? ? ? ? // 從第3級(jí)緩存刪除
? ? ? ? ? ? ? ? this.singletonFactories.remove(beanName);
? ? ? ? ? ? ? ? // 從第2級(jí)緩存刪除
? ? ? ? ? ? ? ? this.earlySingletonObjects.remove(beanName);
? ? ? ? ? ? ? ? // 放入已注冊(cè)的單例池里
? ? ? ? ? ? ? ? this.registeredSingletons.add(beanName);
? ? ? ? ? ? }
? ? ? ? }

(3)“添加到第3級(jí)緩存”的源碼:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
? ? ? ? ? ? synchronized (this.singletonObjects) {
? ? ? ? ? ? ? ? // 若第1級(jí)緩存沒有bean實(shí)例
? ? ? ? ? ? ? ? if (!this.singletonObjects.containsKey(beanName)) {
? ? ? ? ? ? ? ? ? ? // 放入第3級(jí)緩存
? ? ? ? ? ? ? ? ? ? this.singletonFactories.put(beanName, singletonFactory);
? ? ? ? ? ? ? ? ? ? // 從第2級(jí)緩存刪除,確保第2級(jí)緩存沒有該bean
? ? ? ? ? ? ? ? ? ? this.earlySingletonObjects.remove(beanName);
? ? ? ? ? ? ? ? ? ? // 放入已注冊(cè)的單例池里
? ? ? ? ? ? ? ? ? ? this.registeredSingletons.add(beanName);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }

(4)“創(chuàng)建Bean”的源碼:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
? ? BeanWrapper instanceWrapper = null;
? ??
? ? if (instanceWrapper == null) {
? ? ? ? //實(shí)例化對(duì)象
? ? ? ? instanceWrapper = this.createBeanInstance(beanName, mbd, args);
? ? }
?
? ? final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;
? ? Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null;
? ?
? ? //判斷是否允許提前暴露對(duì)象,如果允許,則直接添加一個(gè) ObjectFactory 到第3級(jí)緩存
? ? boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
? ? ? ? ? ? ? ? isSingletonCurrentlyInCreation(beanName));
? ? if (earlySingletonExposure) {
? ? ? ? //添加到第3級(jí)緩存
? ? ? ? addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
? ? }
?
? ? //填充屬性
? ? this.populateBean(beanName, mbd, instanceWrapper);
? ? //執(zhí)行初始化方法,并創(chuàng)建代理
? ? exposedObject = initializeBean(beanName, exposedObject, mbd);
? ? return exposedObject;
}

通過這段代碼,我們可以知道:Spring 在實(shí)例化對(duì)象之后,就會(huì)為其創(chuàng)建一個(gè) Bean 工廠,并將此工廠加入到三級(jí)緩存中。

因此,Spring 一開始提前暴露的并不是實(shí)例化的 Bean,而是將 Bean 包裝起來的ObjectFactory。為什么要這么做呢?

這實(shí)際上涉及到 AOP。如果創(chuàng)建的 Bean 是有代理的,那么注入的就應(yīng)該是代理 Bean,而不是原始的 Bean。但是,Spring一開始并不知道 Bean是否會(huì)有循環(huán)依賴,通常情況下(沒有循環(huán)依賴的情況下),Spring 都會(huì)在“完成填充屬性并且執(zhí)行完初始化方法”之后再為其創(chuàng)建代理。但是,如果出現(xiàn)了循環(huán)依賴,Spring 就不得不為其提前創(chuàng)建"代理對(duì)象";否則,注入的就是一個(gè)原始對(duì)象,而不是代理對(duì)象。因此,這里就涉及到"應(yīng)該在哪里提前創(chuàng)建代理對(duì)象"?

Spring 的做法就是:在 ObjectFactory 中去提前創(chuàng)建代理對(duì)象。它會(huì)執(zhí)行 getObject() 方法來獲取到 Bean。實(shí)際上,它真正執(zhí)行的方法如下:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
? ? Object exposedObject = bean;
? ? if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
? ? ? ? for (BeanPostProcessor bp : getBeanPostProcessors()) {
? ? ? ? ? ? if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
? ? ? ? ? ? ? ? SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
? ? ? ? ? ? ? ? // 如果需要代理,這里會(huì)返回代理對(duì)象;否則,返回原始對(duì)象。
? ? ? ? ? ? ? ? exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return exposedObject;
}

提前進(jìn)行對(duì)象的代理工作,并在 earlyProxyReferences map中記錄已被代理的對(duì)象,是為了避免在后面重復(fù)創(chuàng)建代理對(duì)象。

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
? ? ? ? implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
? ? @Override
? ? public Object getEarlyBeanReference(Object bean, String beanName) {
? ? ? ? Object cacheKey = getCacheKey(bean.getClass(), beanName);
? ? ? ? // 記錄已被代理的對(duì)象
? ? ? ? this.earlyProxyReferences.put(cacheKey, bean);
? ? ? ? return wrapIfNecessary(bean, beanName, cacheKey);
? ? }
}

再次分析獲取bean的方法getSingleton()方法,可知:

提前暴露的對(duì)象,雖然已實(shí)例化,但是沒有進(jìn)行屬性填充,還沒有完成初始化,是一個(gè)不完整的對(duì)象。 這個(gè)對(duì)象存放在二級(jí)緩存中,對(duì)于三級(jí)緩存機(jī)制十分重要,是解決循環(huán)依賴一個(gè)非常巧妙的設(shè)計(jì)。

讓我們來分析一下“A的某個(gè)field或者setter依賴了B的實(shí)例對(duì)象,同時(shí)B的某個(gè)field或者setter依賴了A的實(shí)例對(duì)象”這種循環(huán)依賴的情景。

  • A 調(diào)用doCreateBean()創(chuàng)建Bean對(duì)象:由于還未創(chuàng)建,從第1級(jí)緩存singletonObjects查不到,此時(shí)只是一個(gè)半成品(提前暴露的對(duì)象),放入第3級(jí)緩存singletonFactories。
  • A在屬性填充時(shí)發(fā)現(xiàn)自己需要B對(duì)象,但是在三級(jí)緩存中均未發(fā)現(xiàn)B,于是創(chuàng)建B的半成品,放入第3級(jí)緩存singletonFactories。
  • B在屬性填充時(shí)發(fā)現(xiàn)自己需要A對(duì)象,從第1級(jí)緩存singletonObjects和第2級(jí)緩存earlySingletonObjects中未發(fā)現(xiàn)A,但是在第3級(jí)緩存singletonFactories中發(fā)現(xiàn)A,將A放入第2級(jí)緩存earlySingletonObjects,同時(shí)從第3級(jí)緩存singletonFactories刪除。
  • 將A注入到對(duì)象B中。
  • B完成屬性填充,執(zhí)行初始化方法,將自己放入第1級(jí)緩存singletonObjects中(此時(shí)B是一個(gè)完整的對(duì)象),同時(shí)從第3級(jí)緩存singletonFactories和第2級(jí)緩存earlySingletonObjects中刪除。
  • A得到“對(duì)象B的完整實(shí)例”,將B注入到A中。
  • A完成屬性填充,執(zhí)行初始化方法,并放入到第1級(jí)緩存singletonObjects中。

在創(chuàng)建過程中,都是從第三級(jí)緩存(對(duì)象工廠創(chuàng)建不完整對(duì)象),將提前暴露的對(duì)象放入到第二級(jí)緩存;從第二級(jí)緩存拿到后,完成初始化,并放入第一級(jí)緩存。

spring三級(jí)緩存代碼流程圖

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 淺談Spring事務(wù)傳播行為實(shí)戰(zhàn)

    淺談Spring事務(wù)傳播行為實(shí)戰(zhàn)

    這篇文章主要介紹了淺談Spring事務(wù)傳播行為實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java Redis Redisson配置教程詳解

    Java Redis Redisson配置教程詳解

    這篇文章主要介紹了Java Redis Redisson配置教程,包括Session共享配置及其他Redisson的Config配置方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • java 多線程死鎖詳解及簡(jiǎn)單實(shí)例

    java 多線程死鎖詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了java 多線程死鎖詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法

    IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法

    這篇文章主要介紹了IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Spring原生Rpc六種的正確打開方式實(shí)現(xiàn)示例

    Spring原生Rpc六種的正確打開方式實(shí)現(xiàn)示例

    這篇文章主要為大家展示了Spring原生Rpc六種的正確打開方式實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步早日升職加薪
    2022-02-02
  • Spring Boot Maven插件使用詳解

    Spring Boot Maven插件使用詳解

    這篇文章主要為大家詳細(xì)介紹了Spring Boot Maven插件使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Spring Aware源碼設(shè)計(jì)示例解析

    Spring Aware源碼設(shè)計(jì)示例解析

    這篇文章主要為大家介紹了Spring Aware源碼設(shè)計(jì)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Java多輸入框查詢需求實(shí)現(xiàn)方法詳解

    Java多輸入框查詢需求實(shí)現(xiàn)方法詳解

    這篇文章主要給大家介紹了Java多輸入框查詢需求實(shí)現(xiàn)的相關(guān)資料,文中通過代碼以及圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-10-10
  • java生成驗(yàn)證碼工具類

    java生成驗(yàn)證碼工具類

    這篇文章主要為大家詳細(xì)介紹了java生成驗(yàn)證碼工具類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 解決SpringBoot項(xiàng)目啟動(dòng)后網(wǎng)頁(yè)顯示Please sign in的問題

    解決SpringBoot項(xiàng)目啟動(dòng)后網(wǎng)頁(yè)顯示Please sign in的問題

    這篇文章主要介紹了解決SpringBoot項(xiàng)目啟動(dòng)后網(wǎng)頁(yè)顯示Please sign in的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04

最新評(píng)論