Spring源碼閱讀之循環引用

1、前言java

Spring循環依賴是面試考點之一。面試官能夠深挖面試者對Spring關於Bean的生命週期掌握狀況。Spring循環依賴也是Spring難點之一,邏輯比較繞,須要對Spring Bean的生命週期瞭如指掌。面試

2、什麼是循環依賴?

在這裏插入圖片描述
簡單,就是A對象依賴了B對象,B對象依賴了A對象。

@Component
public class A {
	@Autowired
	B b;
}
複製代碼
@Component
public class B {
	@Autowired
	A a;
}
複製代碼

3、Spring是如何處理循環依賴?

3.1 使用文字描述具體循環依賴的兩個Bean的生命週期流程

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. 添加到單例池
複製代碼

在這裏插入圖片描述

3.2 爲何須要三級緩存來解決循環依賴呢?

三級緩存定義及做用

  • 一級緩存: singletonObjects。存儲已走完Spring生命週期的Bean。注意,對象Bean在Spring的世界是徹底兩個概念。經過反射實例化的叫對象,此時這個對象並未完成Spring的生命週期流程(如後置處理器等),Bean則表示已經完成Spring整個生命週期流程。
  • 二級緩存: earlySingletonObjects。存儲已實例化(經過反射建立的對象)可是未走完Spring生命週期流程的對象。
  • 三級緩存: singletonFactories。存儲對象工廠。目的是在適當的時候經過對象工廠生成AOP代理對象。

如何解決

  1. 經過提早暴露本身的方式(將本身加入三級緩存)讓依賴者注入,從而不會致使死循環,能夠走完剩下流程。
  2. 暴露對象工廠目的是爲了完成AOP代理。對象工廠清楚如何建立對象的AOP代理,可是不會立馬建立,而是到合適的時機進行AOP代理對象的建立。
  3. 二級緩存存在的目的之一是保證對象只有一次AOP代理。當調用三級緩存的getObject()方法返回的對象會存入二級緩存,這樣,當接下來的依賴者調用的時候, 會先判斷二級緩存是否有目標對象,若是存在直接返回。

3.3 重要代碼片斷

代碼① - getSingleton

// 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;
}
複製代碼

代碼② - beforeSingletonCreation

// 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);
    }
}
複製代碼

代碼③ - createBeanInstance

// 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);
}
複製代碼

代碼④ - addSingletonFactory

// 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);
        }
    }
}
複製代碼

代碼⑤ - populateBean

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;
        }
    }
}
複製代碼

代碼⑥ - initializeBean

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;
}
複製代碼

代碼⑦ - doCreateBean

// 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;
        }
        ...
    }
}
...
複製代碼

代碼⑧ - getSingleton

// 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);
    }
}
複製代碼

4、不一樣注入方式與循環依賴關係

依賴注入方式 循環依賴可否被解決
均採用setter方法注入
均採用構造器注入 不能
A中注入B的方式爲setter方法,B中注入A的方式爲構造器
A中注入B的方式爲構造器,B中注入A的方式爲setter方法 不能

注: A先建立。緩存

小結:bash

  1. 主對象(具有循環依賴且最早加載的類,簡稱A)不能經過構造函數的方法注入所依賴的Bean對象(簡稱B),而B不受限制,可使用任意方式注入(setter、@Autowire、構造函數)
  2. 循環依賴中A對象不能使用構造函數注入的緣由是在AbstractAutowireCapableBeanFactory#createBeanInstance方法中作類型推斷時,若是推斷是以構造方法實例B,則會直接調用``AbstractAutowireCapableBeanFactory#autowireConstructor,該方法會經過調用AbstractAutowireCapableBeanFactory#doCreateBean建立對象,可是因爲A對象沒有提早暴露工廠(不給機會呀),因此只能一步步建立,可是走到代碼DefaultSingletonBeanRegistry#getSingletonbeforeSingletonCreation方法時,因爲此時A正在建立集合,強行添加則會返回false`,則拋出異常。相關代碼③

若是解決循環依賴呢?app

  • 延遲構造
  • 使用setter注入

4、總結

  1. Spring團隊建議咱們使用constructor based (構造注入)的方式管理咱們的依賴,對強制依賴使用斷言。這裏推薦使用setter注入。
  2. Spring如何解決循環依賴?
    1. Spring經過三級緩存解決了循環依賴。其餘一級緩存爲單例池,二級緩存爲早期曝光對象,三級緩存爲早期曝光對象工廠。當A、B兩類發生循環引用,在A實例化以後,將本身提前曝光(即加入三級緩存),若是A初始AOP代理,該工廠對象返回的是被代理的對象,若未被代理,返回對象自己。當A進行屬性注入時,通過以前實例化步驟,此時輪到B屬性注入,調用getBean(a)獲取A對象,因爲A處理正在建立集合中,此時也發了循環依賴,因此能夠從三級緩存獲取對象工廠(若是A被AOP代理,此時返回就是代理對象),並把對象放到二級緩存中,這樣保證A只通過一次AOP代理。接下來,B走完Spring生命週期流程,並放入單例池中。當B建立完後,會將B注入A,A走完Spring生命週期流程。到此,循環依賴結束。
相關文章
相關標籤/搜索