欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring中的三級緩存與循環(huán)依賴詳解

 更新時間:2024年05月20日 15:14:47   作者:買斷  
Spring三級緩存是Spring框架中用于解決循環(huán)依賴問題的一種機制,這篇文章主要介紹了Spring三級緩存與循環(huán)依賴的相關知識,本文給大家介紹的非常詳細,需要的朋友可以參考下

一. 前言

Spring 的三級緩存、循環(huán)依賴,我們經常聽到這兩個詞,包括面試也會被面試官問及三級緩存是啥?為啥需要三級緩存?循環(huán)依賴是啥?Spring 是如何解決循環(huán)依賴的?什么樣的循環(huán)依賴 Spring 無法解決?

帶著上述的問題,我們深入看一下 Spring BeanFactory 的 getBean() 流程;這篇文章需要看官有一定的 Spring 源碼了解;

二. 三級緩存是指哪三個

三級緩存其實對應了三個 Map,它是在 DefaultSingletonBeanRegistry 類里作為成員變量的;

public class DefaultSingletonBeanRegistry 
    extends SimpleAliasRegistry 
    implements SingletonBeanRegistry {
    /** Cache of singleton factories: bean name to ObjectFactory. */
    private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    /** Cache of early singleton objects: bean name to bean instance. */
    private Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
    /** Cache of singleton objects: bean name to bean instance. */
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // ...
}
  • 三級緩存 singletonFactories:可以看到存的是 ObjectFactory 對象,第三級緩存可以根據對象是否需要創(chuàng)建代理而提前創(chuàng)建出代理對象;或者是創(chuàng)建出普通對象;
  • 二級緩存 earlySingletonObjects:顧名思義,它存儲的是一個早期對象,存的是半成品對象或者半成品對象的代理對象,用來解決對象創(chuàng)建過程中的循環(huán)依賴問題;(這里為什么說是一個半成品對象,因為這里存儲的對象的屬性可能沒有注入完全);
  • 一級緩存 singletonObjects:這里存的就是成品對象,實例化和初始化都完成了,我們項目中使用的對象都是在一級緩存中獲取的,一級緩存中存放代理對象,普通對象;

三. getBean()流程

我們通過 BeanFactory 的 getBean() 看一下三級緩存的全流程;

直接進入到 AbstractBeanFactory 的 getBean();

// --------------------------- AbstractBeanFactory ---------------------------
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
// --------------------------- AbstractBeanFactory ---------------------------
protected <T> T doGetBean(
    String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) {
    // ...
    // 我們直接看主流程
    // Create bean instance.
    if (mbd.isSingleton()) {
        // 這里調用 DefaultSingletonBeanRegistry#getSingleton()
        // 參數一為 beanName
        // 參數二為 ObjectFactory 函數式對象
        sharedInstance = getSingleton(beanName, () -> {
            try {
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                destroySingleton(beanName);
                throw ex;
            }
        });
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    // ...
}

在 AbstractBeanFactory#doGetBean() 中調用了 DefaultSingletonBeanRegistry#getSingleton(),并且這個 getSingleton() 的參數二是一個 ObjectFactory 函數式對象,這個函數式對象的實現邏輯是 return createBean();

我們先看 DefaultSingletonBeanRegistry#getSingleton();

// ------------------------ DefaultSingletonBeanRegistry -----------------------
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        // 1. 先從一級緩存中去獲取
        // 如果獲取到了 bean 對象,直接返回
        // 沒有獲取到 bean 對象的話,進入后續(xù)創(chuàng)建 bean 對象流程
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException();
            }
            // ...
            try {
                // 2. 調用 ObjectFactory 對象的 getObject() 創(chuàng)建得到 bean 對象
                // 從上述分析我們知道最終實現是 return createBean()
                // 我們需要看 createBean() 流程
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } catch (IllegalStateException ex) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            } finally {
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 3. 創(chuàng)建 bean 成功的情況下
                // 將 bean 對象放入到一級緩存 singletonObjects 中
                // 并將 beanName 對應的值從二級緩存、三級緩存中移除
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}
// ------------------------ DefaultSingletonBeanRegistry -----------------------
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        // 將 bean 對象放入一級緩存中
        // 并將 beanName 對應的值從二級緩存、三級緩存中移除
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

核心實現是 ObjectFactory 的 createBean(),我們看 createBean() 邏輯;

// --------------------- AbstractAutowireCapableBeanFactory -------------------
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    RootBeanDefinition mbdToUse = mbd;
    // ...
    try {
        // 調用 doCreateBean() 創(chuàng)建出 bean 對象,并返回該 bean 對象
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        return beanInstance;
    } catch (Throwable ex) {
        throw new BeanCreationException();
    }
}
// --------------------- AbstractAutowireCapableBeanFactory -------------------
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, 
                              Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 1. 實例化對象
        // 根據合適的構造方法構造出實例 bean 對象
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
    // 2. 是否應該使用三級緩存,一般情況下都會使用三級緩存
    boolean earlySingletonExposure = (mbd.isSingleton() && 
                                      this.allowCircularReferences &&
                                      isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        // 3. 將 beanName 和對應的函數式對象 ObjectFactory 放入到三級緩存中
        // 該 ObjectFactory 已經拿到了剛剛實例化好的 bean 對象,只不過只執(zhí)行了構造函數
        // 該 ObjectFactory 的 getObject() 實現是調用 getEarlyBeanReference()
        addSingletonFactory(beanName,
                            () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    // 4. 初始化 Bean 對象 
    Object exposedObject = bean;
    try {
        // 4.1 屬性注入
        // 如果 A 依賴 B,getBean(A) 時會去調 getBean(B)
        // 如果 A、B 出現循環(huán)依賴,會出現 getBean(A) -> getBean(B) -> getBean(A) 的情況
        populateBean(beanName, mbd, instanceWrapper);
        // 4.2 初始化 bean 對象
        // 這里會執(zhí)行一些 BeanPostProcessor 的后處理方法
        // 我們熟悉的 Spring AOP 就是在這里生成的代理類對象的
        // 如 @Transactional 使用的后處理器是 AbstractAutoProxyCreator
        // 如 @Async 使用的后處理器是 AbstractAdvisingBeanPostProcessor
        // 雖然都是生成 AOP 對象,但是這兩者在處理循環(huán)依賴時處理邏輯不一樣,后面細講
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        throw ex;
    }
    if (earlySingletonExposure) {
        // 5. 決定 getBean(A) 是返回 bean 對象還是拋出異常
        // 參數二是 false
        // 從一級緩存或者二級緩存中獲取 bean 對象
        // 走到這里一般是嘗試從二級緩存中獲取 bean 對象
        // 這里比較繞,我們后面再講
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && 
                     hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>();
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException();
                }
            }
        }
    }
    // 6. 注冊刪除 bean 邏輯
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException();
    }
    // 7. 返回 bean 對象
    return exposedObject;
}

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

相關文章

  • 解決feignclient調用服務,傳遞的中文數據成???問題

    解決feignclient調用服務,傳遞的中文數據成???問題

    這篇文章主要介紹了解決feignclient調用服務,傳遞的中文數據成???問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java堆排序算法詳解

    Java堆排序算法詳解

    這篇文章主要為大家詳細介紹了Java堆排序算法的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Servlet+JavaBean+JSP打造Java Web注冊與登錄功能

    Servlet+JavaBean+JSP打造Java Web注冊與登錄功能

    比作MVC的話,控制器部分采用Servlet來實現,模型部分采用JavaBean來實現,而大部分的視圖采用Jsp頁面來實現,接下來我們就來詳細看看如何用Servlet+JavaBean+JSP打造Java Web注冊與登錄功能
    2016-05-05
  • Java實現用Mysql存取圖片操作實例

    Java實現用Mysql存取圖片操作實例

    這篇文章主要介紹了Java實現用Mysql存取圖片操作實例,本文講解了使用BLOB類型保存和讀取圖片的代碼實例,需要的朋友可以參考下
    2015-06-06
  • 詳解spring cloud中使用Ribbon實現客戶端的軟負載均衡

    詳解spring cloud中使用Ribbon實現客戶端的軟負載均衡

    這篇文章主要介紹了詳解spring cloud中使用Ribbon實現客戶端的軟負載均衡,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 參數校驗Spring的@Valid注解用法解析

    參數校驗Spring的@Valid注解用法解析

    這篇文章主要介紹了參數校驗Spring的@Valid注解用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Idea公司真牛逼發(fā)行最適合程序員編程字體

    Idea公司真牛逼發(fā)行最適合程序員編程字體

    JetBrains年初的時候推出了一種新字體,即JetBrains Mono,它是專為開發(fā)人員設計的,非常不錯,喜歡的朋友快來體驗吧
    2020-12-12
  • Java多線程并發(fā)synchronized?關鍵字

    Java多線程并發(fā)synchronized?關鍵字

    這篇文章主要介紹了Java多線程并發(fā)synchronized?關鍵字,Java?在虛擬機層面提供了?synchronized?關鍵字供開發(fā)者快速實現互斥同步的重量級鎖來保障線程安全。
    2022-06-06
  • java實現在線聊天系統(tǒng)

    java實現在線聊天系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現在線聊天系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • SpringBoot AOP使用筆記

    SpringBoot AOP使用筆記

    今天小編就為大家分享一篇關于SpringBoot AOP使用筆記,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評論