java 注入 循环_spring依赖注入——循环依赖
上一篇博客簡單地分析了下依賴注入。但是對于依賴注入的很多細節,都沒有深入的分析。這一篇博客會繼續分析spring的依賴注入。這篇博客會解決分析getBean緩存時候遺留下來的循環依賴問題。
循環依賴分析
首先明確下,只有單例情況下,spring才會試著去解決循環依賴問題,多例是不會去解決循環依賴的。這個也好理解,如果是多例的話,比如a -> b 并且 b -> a 那么,當A a=new A(); 之后要注入b,b卻是多例的,那么究竟該注入哪個B是不確定的。如下圖:
接下來我們分析,為啥會有循環依賴的問題。
先來分析沒有循環依賴的問題public?static?class?A{
private?B?b;????//省略get和set方法}public?static?class?B{
}
這個時候,如果spring先初始化A,然后會發現A依賴于B,然后就會初始化B,最后注入到A里。
整個流程用代碼表示大概如下所示:A?a?=?創建A
B?b?=?創建B
----->?創建A子流程??a.setB(b);
但是假設B也依賴了A呢?即public?static?class?B{
private?A?a;
}
那樣依賴注入過程就會變成(簡單示例)A?a?=?創建A
B?b?=?創建B
---->??創建B子流程?b.setA(????);??//??這個時候A還沒創建完成呢a.setB(b);
那么如何解決呢?很簡單,把那個還沒創建完的A(只是new了,但是沒有進行依賴注入的A)set到B里就好了。
弄清了這個流程之后,我們再來分析spring是如何進行依賴注入的。
spring對引用類型的注入
這里我先從spring對引用屬性的注入開始。
即ref的注入private?Object?resolveReference(Object?argName,?RuntimeBeanReference?ref)?{????try?{????????String?refName?=?ref.getBeanName();
refName?=?String.valueOf(doEvaluate(refName));????????if?(ref.isToParent())?{????????????if?(this.beanFactory.getParentBeanFactory()?==?null)?{????????????????throw?new?BeanCreationException(????????????????????????this.beanDefinition.getResourceDescription(),?this.beanName,????????????????????????"Can't?resolve?reference?to?bean?'"?+?refName?+????????????????????????"'?in?parent?factory:?no?parent?factory?available");
}????????????return?this.beanFactory.getParentBeanFactory().getBean(refName);
}????????else?{????????????Object?bean?=?this.beanFactory.getBean(refName);????????????this.beanFactory.registerDependentBean(refName,?this.beanName);????????????return?bean;
}
}????catch?(BeansException?ex)?{????????throw?new?BeanCreationException(????????????????this.beanDefinition.getResourceDescription(),?this.beanName,????????????????"Cannot?resolve?reference?to?bean?'"?+?ref.getBeanName()?+?"'?while?setting?"?+?argName,?ex);
}
}
實現很簡單,就是從beanFactory里獲取要依賴的對象
我們再來回顧下流程
問題是,當走到6時候,似乎又會回到1,這樣不就死循環了么?
重點就是,第六步的獲取A,我們回到doGetBean方法中。
getSingleton 方法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?!=?NULL_OBJECT???singletonObject?:?null);
}
我們在分析初始化bean的緩存部分時,曾分析過這幾個緩存。當時其實只知道了singletonObjects是存儲了已經創建了的對象。
現在讓我們回頭再看看這些緩存。
首先看看singletonFactories賦值的地方。
doCreateBean//?Eagerly?cache?singletons?to?be?able?to?resolve?circular?references//?even?when?triggered?by?lifecycle?interfaces?like?BeanFactoryAware.boolean?earlySingletonExposure?=?(mbd.isSingleton()?&&?this.allowCircularReferences?&&
isSingletonCurrentlyInCreation(beanName));if?(earlySingletonExposure)?{????if?(logger.isDebugEnabled())?{
logger.debug("Eagerly?caching?bean?'"?+?beanName?+????????????????"'?to?allow?for?resolving?potential?circular?references");
}
addSingletonFactory(beanName,?new?ObjectFactory()?{????????@Override
public?Object?getObject()?throws?BeansException?{????????????//默認實現返回bean
return?getEarlyBeanReference(beanName,?mbd,?bean);
}
});
}
在創建bean時候,有這樣一段代碼,當需要進行提前暴露時候(當前創建對象單例 + 允許循環引用 + 當前類正在被創建)會調用addSingletonFactory方法protected?void?addSingletonFactory(String?beanName,?ObjectFactory>?singletonFactory)?{
Assert.notNull(singletonFactory,?"Singleton?factory?must?not?be?null");????synchronized?(this.singletonObjects)?{????????if?(!this.singletonObjects.containsKey(beanName))?{????????????this.singletonFactories.put(beanName,?singletonFactory);????????????this.earlySingletonObjects.remove(beanName);????????????this.registeredSingletons.add(beanName);
}
}
}
這里就碰見了我們要分析的singletonFactories,它存儲了beanName -> 此處的匿名內部類singletonFactory。
singletonFactory
我們再回到getSingleton方法,以及之前繪制的圖ObjectFactory>?singletonFactory?=?this.singletonFactories.get(beanName);if?(singletonFactory?!=?null)?{
singletonObject?=?singletonFactory.getObject();????this.earlySingletonObjects.put(beanName,?singletonObject);????this.singletonFactories.remove(beanName);
}
邏輯很簡單
三級緩存
我們經常聽說spring通過三級緩存解決了循環依賴,其實三級緩存非常簡單。就是指我們分析過的Map singletonObjects
Map> singletonFactories
Map earlySingletonObjects
這里分別舉這樣三個例子。
A 依賴 B(B不依賴A)
一級緩存
A 依賴 B && B依賴A
三級緩存
A依賴B && B依賴A + B依賴C && C 依賴 A
作者:端吉
鏈接:https://www.jianshu.com/p/10f94b776e55
總結
以上是生活随笔為你收集整理的java 注入 循环_spring依赖注入——循环依赖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows11动态磁贴替代软件大盘点
- 下一篇: python 命名实体识别_使用Pyth