1、前言java
Spring循環依賴
是面試考點之一。面試官能夠深挖面試者對Spring
關於Bean的生命週期
掌握狀況。Spring循環依賴
也是Spring
難點之一,邏輯比較繞,須要對Spring Bean
的生命週期瞭如指掌。面試
@Component
public class A {
@Autowired
B b;
}
複製代碼
@Component
public class B {
@Autowired
A a;
}
複製代碼
A 生命週期
1. class文件
2. 經過beanName去緩存中獲取對象。一開始,單例池沒有,且a也沒有處於正在建立集合中,因此不會去二級緩存、三級緩存拿對象,相關代碼[標記①]
3. 把對象放到正在建立集合中(beforeSingletonCreation(beanName);) 相關代碼[標記②]
4. 經過反射實例化對象(createBeanInstance();) 相關代碼[標記③]
5. 添加對象工廠到二級緩存中 相關代碼[標記④]
6. 屬性填充。在這裏發現須要B對象,從單例池獲取B->null->且b也沒有處於正在建立集合中->實例化B且完成B的生命週期 相關代碼[標記⑤]
wait for b init...
7. 初始化 相關代碼[標記⑥]
8. 從二級緩存中獲取Bean 相關代碼[標記⑦]
9. 添加到單例池 相關代碼[標記⑥]
B 生命週期
1. class文件
2. 經過beanName去緩存中獲取對象。一開始,單例池沒有,且a也沒有處於正在建立集合中,因此不會去二級緩存、三級緩存拿
3. 把對象放到正在建立集合中(beforeSingletonCreation(beanName);)
(singletonObject = singletonFactory.getObject();)
4. 經過反射實例化對象(createBeanInstance();)
5. 添加對象工廠到二級緩存中
6. 屬性填充。在這裏發現須要A對象,從單例池獲取A->null->此時a在正在建立集合中->從三級緩存中獲取對象(若是a存在切面,則返回代理對象),將對象放至二級緩存,刪除三級緩存
7. 初始化
8. 從二級緩存中獲取Bean
9. 添加到單例池
複製代碼
singletonObjects
。存儲已走完Spring
生命週期的Bean
。注意,對象
和Bean
在Spring的世界是徹底兩個概念。經過反射實例化的叫對象,此時這個對象並未完成Spring
的生命週期流程(如後置處理器等),Bean
則表示已經完成Spring
整個生命週期流程。earlySingletonObjects
。存儲已實例化(經過反射建立的對象)可是未走完Spring
生命週期流程的對象。singletonFactories
。存儲對象工廠
。目的是在適當的時候經過對象工廠生成AOP
代理對象。AOP
代理。對象工廠清楚如何建立對象的AOP代理,可是不會立馬建立,而是到合適的時機進行AOP
代理對象的建立。二級緩存存
在的目的之一是保證對象只有一次AOP
代理。當調用三級緩存的getObject()
方法返回的對象會存入二級緩存,這樣,當接下來的依賴者調用的時候, 會先判斷二級緩存
是否有目標對象,若是存在直接返回。// DefaultSingletonBeanRegistry#getSingleton
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 從一級緩存中獲取bean,即單例池
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;
}
複製代碼
// DefaultSingletonBeanRegistry#beforeSingletonCreation
protected void beforeSingletonCreation(String beanName) {
// 1.inCreationCheckExclusions: 判斷當前對象是否存在 [被剔除] 集合對象中 註解 excludeFilters=xx
// 2.singletonsCurrentlyInCreation: 將當前對象添加 [正在建立單例Bean] 集合中
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
複製代碼
// AbstractAutowireCapableBeanFactory#createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 若是爲自動裝配,則推斷出來各類候選的構造方法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 利用推斷出來的修行構造方法去實例化對象。若是使用構造器注入,這裏直接返回
return autowireConstructor(beanName, mbd, ctors, args);
}
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 利用推斷出來的候選構造方法去實例化對象
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 若是沒有推斷出合適的構造方法(或者沒有提供特殊的構造方法),則使用默認的構造方法
return instantiateBean(beanName, mbd);
}
複製代碼
// DefaultSingletonBeanRegistry#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);
}
}
}
複製代碼
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 這裏會有三個後置處理器,分別是:
// 一、ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
// 二、AutowiredAnnotationBeanPostProcessor
// 三、CommonAnnotationBeanPostProcessor
// AutowiredAnnotationBeanPostProcessor: 解析@Autowire屬性注入
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// 屬性自動注入主要使用 AutowiredAnnotationBeanPostProcessor後置處理器
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
複製代碼
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 4-一、執行Aware (BeanNameAware、BeanClassLoaderAware 、BeanFactoryAware)
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 4.2 初始化前
// △△ 執行Bean後置處理器(lifeCycle Callback)
// 重寫這個方法[postProcessBeforeInitialization]則會在這裏被調用
// lifeCycle callback init by annotation
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 4.三、初始化 [InitializingBean]
// lifeCycle callback init by interface.
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 4.四、初始化後
// 完成AOP,生成動態代理; 事件發佈; 監聽
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
複製代碼
// AbstractAutowireCapableBeanFactory#doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
if (earlySingletonExposure) {
// 在解決循環依賴時,獲取beanName從二級緩存中獲取
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
...
}
}
...
複製代碼
// DefaultSingletonBeanRegistry#getSingleton
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 把當前對象放到 [正在建立] 的集合(singletonsCurrentlyInCreation)當中
beforeSingletonCreation(beanName);
// getObject方法會調用AbstractAutowireCapableBeanFactory的createBean方法
singletonObject = singletonFactory.getObject();
//添加到單例池
addSingleton(beanName, singletonObject);
}
}
複製代碼
依賴注入方式 | 循環依賴可否被解決 |
---|---|
均採用setter方法注入 | 能 |
均採用構造器注入 | 不能 |
A中注入B的方式爲setter方法,B中注入A的方式爲構造器 | 能 |
A中注入B的方式爲構造器,B中注入A的方式爲setter方法 | 不能 |
注:
A
先建立。緩存小結:bash
- 主對象(具有循環依賴且最早加載的類,簡稱A)不能經過
構造函數
的方法注入所依賴的Bean對象(簡稱B),而B不受限制,可使用任意方式注入(setter、@Autowire、構造函數)
。- 循環依賴中A對象不能使用
構造函數
注入的緣由是在AbstractAutowireCapableBeanFactory#createBeanInstance
方法中作類型推斷時,若是推斷是以構造方法實例B,則會直接調用``AbstractAutowireCapableBeanFactory#autowireConstructor,該方法會經過調用
AbstractAutowireCapableBeanFactory#doCreateBean建立對象,可是因爲A對象沒有提早暴露工廠(不給機會呀),因此只能一步步建立,可是走到代碼
DefaultSingletonBeanRegistry#getSingleton的
beforeSingletonCreation方法時,因爲此時A正在建立集合,強行添加則會返回
false`,則拋出異常。相關代碼③
若是解決循環依賴呢?app
setter
注入Spring
團隊建議咱們使用constructor based (構造注入)
的方式管理咱們的依賴,對強制依賴使用斷言。這裏推薦使用setter
注入。Spring
經過三級緩存
解決了循環依賴。其餘一級緩存爲單例池,二級緩存爲早期曝光對象,三級緩存爲早期曝光對象工廠。當A、B兩類發生循環引用,在A實例化以後,將本身提前曝光(即加入三級緩存),若是A初始AOP
代理,該工廠對象返回的是被代理的對象,若未被代理,返回對象自己。當A進行屬性注入時,通過以前實例化步驟,此時輪到B屬性注入,調用getBean(a)
獲取A對象,因爲A處理正在建立集合中,此時也發了循環依賴,因此能夠從三級緩存獲取對象工廠(若是A被AOP代理,此時返回就是代理對象),並把對象放到二級緩存中,這樣保證A只通過一次AOP代理。接下來,B走完Spring
生命週期流程,並放入單例池中。當B建立完後,會將B注入A,A走完Spring
生命週期流程。到此,循環依賴結束。