您好,登錄后才能下訂單哦!
這篇文章運用簡單易懂的例子給大家介紹spring如何解決循環(huán)依賴,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
概述
循環(huán)依賴就是依賴關系形成環(huán),比如最簡單的循環(huán)依賴:A對象依賴B,B對象依賴A
屬性注入與循環(huán)依賴
spring屬性注入處理循環(huán)依賴的方式
通過以下xml方式配置一個循環(huán)依賴的示例:
<bean id="person1" class="com.example.leetcode.spring.bean.Person"> <property name="parent" ref="person2"></property> <property name="name" value="tom"></property> </bean> <bean id="person2" class="com.example.leetcode.spring.bean.Person"> <property name="parent" ref="person1"></property> <property name="name" value="jack"></property> </bean>
spring循環(huán)依賴處理幾個關鍵位置:
獲取bean對象
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // 這里會檢查單例bean是否已經(jīng)在注冊表,并返回。 // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } ... }
DefaultSingletonBeanRegistry(單例對象注冊表)的幾個關鍵屬性。
// 用來存儲已經(jīng)創(chuàng)建好的單例對象 /** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 用來存儲單例beanname到ObjectFactory的映射 /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 用來提前存儲還未初始化好的單例對象 /** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
DefaultSingletonBeanRegistry.getSingleton()的實現(xiàn).
protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
AbstractAutowireCapableBeanFactory.doCreateBean創(chuàng)建對象與注入屬性
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { ... instanceWrapper = createBeanInstance(beanName, mbd, args); ... // 檢查是否提前將單例bean存入緩存 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // 這里將beanname與工廠映射放入緩存注冊表中(也就是上面的singletonFactories) addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } ... // 注入依賴屬性 populateBean(beanName, mbd, instanceWrapper); ... }
假設我們從beanfactory獲取person1對象, 循環(huán)依賴處理流程如下:
1.通過AbstractBeanFactory.doGetBean("persion1")獲取對象
2.因為一開始通過DefaultSingletonBeanRegistry.getSingleton()什么都沒有,進入AbstractAutowireCapableBeanFactory.doCreateBean()進行創(chuàng)建
3.AutowireCapableBeanFactory.doCreateBean()里面執(zhí)行完創(chuàng)建邏輯,因為是singleton將beanname與工廠的映射加入到addSingletonFactory()到緩存
4.開始處理person1對象的屬性依賴populateBean()
5.當發(fā)現(xiàn)person1的parent屬性是一個引用時,通過beanfactory.getBean("person2")獲取依賴對象(org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveReference)
6.此時進入person2的創(chuàng)建流程, person2也沒有緩存,開始實例化并加入到addSingletonFactory()到緩存
7.person2在通過populateBean()注入屬性依賴發(fā)現(xiàn)依賴person1, 此時通過beanfactory.getBean("person1")獲取依賴對象
8.此時AbstractBeanFactory.doGetBean("persion1")獲取對象執(zhí)行到getSingleton("person1")進行以下判斷:
9.此時從getSingleton("person1")返回了一個僅實例化尚未注入的bean引用
10.person2在第7步獲取到person1僅實例化未注入的對象引用。
11.person2完成屬性注入并返回。
12.person2被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)緩存,并刪除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);
13.person1在5步獲取到person2的對象并完成屬性注入
14.person1對象返回(因為一開始person2獲取的是person1的引用,此時person1完成注入是能看到注入后的對象)
15.person1被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)緩存,并刪除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);
16.返回最終的person1對象
關于三個map(三級緩存)
在出現(xiàn)循環(huán)依賴時,三個map之間的流程如下:
先從singletonFactories獲取工廠,并通過getObject獲取對象并移除緩存,將對象緩存到earlySingletonObjects
通過earlySingletonObjects獲取提前曝光的對象
對象創(chuàng)建并初始化完成之后,對象信息保留在singletonObjects并移除過earlySingletonObjects中的緩存
earlySingletonObjects二級緩存是雞肋嗎?
earlySingletonObjects緩存的目的是,通過三級緩存在獲取對象會執(zhí)行一些列的后置處理器,通過earlySingletonObjects來緩存提升性能。
關于spring如何解決循環(huán)依賴就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。