大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專(zhuān)注Java教育14年 全國(guó)咨詢/投訴熱線:400-8080-105
動(dòng)力節(jié)點(diǎn)LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁(yè) hot資訊 Spring的三級(jí)緩存和循環(huán)依賴

Spring的三級(jí)緩存和循環(huán)依賴

更新時(shí)間:2021-06-16 12:35:23 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1191次

1. 循環(huán)依賴

什么是依賴注入?假設(shè)有兩個(gè)類(lèi)A和B,A在實(shí)例化的時(shí)候需要B的實(shí)例,而B(niǎo)在實(shí)例化時(shí)又需要A的實(shí)例,在類(lèi)的實(shí)例化過(guò)程就陷入死循環(huán)。這也就是傳統(tǒng)邏輯上的,“到底是先有雞,還是先有蛋”的問(wèn)題?

下面舉一個(gè)例子,定義了兩個(gè)類(lèi)Type和Org:

// Org.java
@Data
@Component
public class Org {
    private final Role role;

    public Org(Role role) {
        this.role = role;
    }
}
// Role.java
@Data
@Component
public class Role {
    private final Org org;
    public Role(Org org) {
        this.org = org;
    }
}

這是spring中典型的構(gòu)造器注入方式,其實(shí)也代表了普通非spring bean之間,相互依賴時(shí)的實(shí)例化過(guò)程,但結(jié)果在運(yùn)行的時(shí)候直接報(bào)循環(huán)依賴的錯(cuò)誤:

***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
   demoController (field private pers.kerry.exercise.springexercise.pojo.Org pers.kerry.exercise.springexercise.controller.DemoController.org)
┌─────┐
|  org defined in file [/Users/kerry/code/idea/spring-exercise/target/classes/pers/kerry/exercise/springexercise/pojo/Org.class]
↑     ↓
|  role defined in file [/Users/kerry/code/idea/spring-exercise/target/classes/pers/kerry/exercise/springexercise/pojo/Role.class]
└─────┘

而如果我們改一下代碼,把構(gòu)造器注入方式改成基于屬性的注入(@Autowired、@Resouce),奇怪的是不報(bào)錯(cuò)了,而且相互依賴的兩個(gè)bean 都實(shí)例化成功了。說(shuō)明spring框架有解決循環(huán)依賴的問(wèn)題,我們了解spring解決循環(huán)依賴的過(guò)程,其實(shí)有助于進(jìn)一步了解spring 中 bean的活動(dòng)過(guò)程。

2. 三級(jí)緩存

我們?cè)谥敖榻BBean的生命周期時(shí)說(shuō)過(guò),spring 中 bean的實(shí)例化過(guò)程,并非只是調(diào)用構(gòu)造方法。除去spring框架本身提供的一些鉤子或擴(kuò)展方法,簡(jiǎn)單分成下面三個(gè)核心方法:

Spring在創(chuàng)建Bean的過(guò)程中分為三步

實(shí)例化,對(duì)應(yīng)方法:AbstractAutowireCapableBeanFactory中的createBeanInstance方法,簡(jiǎn)單理解就是new了一個(gè)對(duì)象。

屬性注入,對(duì)應(yīng)方法:AbstractAutowireCapableBeanFactory的populateBean方法,為實(shí)例化中new出來(lái)的對(duì)象填充屬性和注入依賴。

初始化,對(duì)應(yīng)方法:AbstractAutowireCapableBeanFactory的initializeBean,執(zhí)行aware接口中的方法,初始化方法,完成AOP代理。

從單例Bean的初始化來(lái)看,主要可能發(fā)生循環(huán)依賴的環(huán)節(jié)就在第二步populate。值得注意的是,基于構(gòu)造方法注入的方式,其實(shí)是將第一步和第二步同時(shí)進(jìn)行,因此馬上就拋出錯(cuò)誤。而spring通過(guò)基于屬性注入的方式,是否有其他特殊的處理呢,我們這時(shí)候就要提到spring的三級(jí)緩存:

private final Map singletonObjects = new ConcurrentHashMap<>(256);

private final Map earlySingletonObjects = new HashMap<>(16);

private final Map> singletonFactories = new HashMap<>(16);

3. 核心方法:getSingleton

我們?cè)讷@取bean實(shí)例的時(shí)候,其實(shí)是先從三級(jí)緩存中獲取,getBean 方法的邏輯如下:

Object sharedInstance = getSingleton(beanName);
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 查詢緩存中是否有創(chuàng)建好的單例
    Object singletonObject = this.singletonObjects.get(beanName);
    // 如果緩存不存在,判斷是否正在創(chuàng)建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 加鎖防止并發(fā)
        synchronized (this.singletonObjects) {
            // 從earlySingletonObjects中查詢是否有early緩存
            singletonObject = this.earlySingletonObjects.get(beanName);
            // early緩存也不存在,且允許early引用
            if (singletonObject == null && allowEarlyReference) {
                // 從單例工廠Map里查詢beanName
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // singletonFactory存在,則調(diào)用getObject方法拿到單例對(duì)象
                    singletonObject = singletonFactory.getObject();
                    // 將單例對(duì)象添加到early緩存中
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    // 移除單例工廠中對(duì)應(yīng)的singletonFactory
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

只針對(duì)單例的bean,多例的后面討論

默認(rèn)的singletonObjects緩存不存在要get的beanName時(shí),判斷beanName是否正在創(chuàng)建中

從early緩存earlySingletonObjects中再查詢,early緩存是用來(lái)緩存已實(shí)例化但未組裝完成的bean

如果early緩存也不存在,從singletonFactories中查找是否有beanName對(duì)應(yīng)的ObjectFactory對(duì)象工廠

如果對(duì)象工廠存在,則調(diào)用getObject方法拿到bean對(duì)象

將bean對(duì)象加入early緩存,并移除singletonFactories的對(duì)象工廠

這是 getBean的邏輯,三級(jí)緩存中一級(jí)一級(jí)地找匹配的Bean,直到最后一級(jí)緩存,通過(guò)匹配beanName 的 ObjectFactory 來(lái)獲取Bean。那么singletonFactories何時(shí)放入了可以通過(guò)getObject獲得bean對(duì)象的ObjectFactory呢?

4. 核心方法:doCreateBean

Bean的實(shí)例化,實(shí)際執(zhí)行的源碼是AbstractAutowireCapableBeanFactory類(lèi)的doCreateBean方法:

 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        // 1、創(chuàng)建一個(gè)對(duì)bean原始對(duì)象的包裝對(duì)象-BeanWrapper,執(zhí)行createBeanInstance,即構(gòu)造方法或工廠方法,給BeanWrapper賦值
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        // 2、允許其他修改beanDefinition,如使用Annotation增強(qiáng)Bean定義等,這通過(guò)類(lèi)MergedBeanDefinitionPostProcessor來(lái)完成
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }

                mbd.postProcessed = true;
            }
        }
        // 3、將當(dāng)前bean 的 ObjetFactory放入singletonFactories中, 
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }
        Object exposedObject = bean;
        // 4、執(zhí)行 populateBean,設(shè)置屬性值
        // 5、執(zhí)行 initializeBean,調(diào)用 Bean的初始化方法
        try {
            this.populateBean(beanName, mbd, instanceWrapper);
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }
        // 6、再次處理循環(huán)依賴問(wèn)題
        if (earlySingletonExposure) {
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;
                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }

                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }
        // 7、注冊(cè)bean的銷(xiāo)毀回調(diào)方法,在beanFactory中注冊(cè)銷(xiāo)毀通知,以便在容器銷(xiāo)毀時(shí),能夠做一些后續(xù)處理工作
        try {
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

BeanWrapper

BeanWrapper接口,作為spring內(nèi)部的一個(gè)核心接口,正如其名,它是bean的包裹類(lèi),即在內(nèi)部中將會(huì)保存該bean的實(shí)例,提供其它一些擴(kuò)展功能。同時(shí),BeanWrapper接口還繼承了PropertyAccessor, propertyEditorRegistry, TypeConverter、ConfigurablePropertyAccessor接口,所以它還提供了訪問(wèn)bean的屬性值、屬性編輯器注冊(cè)、類(lèi)型轉(zhuǎn)換等功能。

我們回顧一下bean的實(shí)例化過(guò)程:

ResourceLoader加載配置信息

BeanDefinitionReader讀取并解析標(biāo)簽,并將標(biāo)簽的屬性轉(zhuǎn)換為BeanDefinition對(duì)應(yīng)的屬性,并注冊(cè)到BeanDefinitionRegistry注冊(cè)表中。

容器掃描BeanDefinitionRegistry注冊(cè)表,通過(guò)反射機(jī)制獲取BeanFactoryPostProcessor類(lèi)型的工廠后處理器,并用這個(gè)工廠后處理器對(duì)BeanDefinition進(jìn)行加工。

根據(jù)處理過(guò)的BeanDefinition,實(shí)例化bean。然后BeanWrapper結(jié)合BeanDefinitionRegistry和PropertyEditorRegistry對(duì)Bean的屬性賦值。

以上就是動(dòng)力節(jié)點(diǎn)小編介紹的"Spring的三級(jí)緩存和循環(huán)依賴",希望對(duì)大家有幫助,如有疑問(wèn),請(qǐng)?jiān)诰€咨詢,有專(zhuān)業(yè)老師隨時(shí)為您服務(wù)。

提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)

免費(fèi)課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 伊人久久亚洲综合天堂 | 久久久国产精品四虎 | 全黄一级裸片视频在线观看 | 日韩精品久久不卡中文字幕 | 国产精品婷婷久久爽一下 | 亚洲视频在线观 | 国产自愉自愉全免费高清 | 亚洲精品中文字幕不卡在线 | 福利在线免费视频 | 69色视频日韩在线视频 | 五月天久久婷婷 | 四虎在线影视在线影库 | 欧美国产伦久久久久 | 夜夜爱夜夜操 | 四虎.com | 美国一级毛片免费看成人 | 不卡高清av手机在线观看 | 精品国产日韩久久亚洲 | 男人边吃奶边爱边做视频日韩 | 欧美日韩生活片 | 亚洲国产欧美日韩一区二区三区 | 欧美日韩久久毛片 | 老子影院午夜伦手机不卡6080 | 亚洲另类中文字幕 | 国产成人毛片视频不卡在线 | 综合久久2o19 | 亚洲视频中文字幕在线观看 | 一级黄色片免费 | 国产成人精品一区二区免费 | 久久综合九色综合亚洲小说 | 国产女人伦码一区二区三区不卡 | 99视频一区 | 99热最新 | 久久最近最新中文字幕大全 | 四虎永久免费影院在线 | 日韩一区二区三区在线观看 | 久久99精品麻豆国产 | 日韩视频久久 | 日本亚欧乱色视频在线网站 | 又粗又大的机巴好爽欧美 | 国产色啪午夜免费视频 |