spring循环依赖

出现循环依赖的情况

 1 // setter方式注入
 2 @Component("A")
 3 public static class A {
 4     
 5     @Autowired
 6     private B b;
 7 }
 8 
 9 @Component("B")
10 public static class B {
11     
12     @Autowired
13     private A a;
14 }
15 //构造器方式注入
16 @Component("A")
17 public static class A {
18     
19     private final B b;
20 
21     @Autowired
22     public A(B b) {
23         this.b = b;
24     }
25 }
26 
27 @Component("B")
28 public static class B {
29     
30     private final A a;
31 
32     @Autowired
33     public B(A a) {
34         this.a = a;
35     }
36 }

如上代码所示,两个bean之间互相注入即为循环依赖。

  废话不多说,实验对象时两个bean,实验变量有三个:

  1. 注入方式:setter注入、构造器注入

  2. 是否是懒加载

  3. 是否是单例

每个变量有四种情况,一共4x4x4=64种情况先说结论:

  1. 如果采用构造器方式注入,必然会出现循环依赖问题。

  2. 如果采用setter方式注入,结论如下:

  1)如果bean都不是单例,注入失败

  2)如果bean都是单例,注入成功

  3)如果bean一个是单例一个是非单例(prototype)且非单例bean比单例bean先创建,注入失败,否则注入成功(对应代码就是单例bean是懒加载,spring容器启动不会创建prototype的bean,如果程序先使用prototype的bean,那么注入会失败)

  3. 如果一个采用构造器注入一个采用setter注入,一共3x4x4=48种情况,情况太多,无法罗列,但是无妨。理解原理才是理工科的重点,结论只是检验理解的工具。

原因分析

  首先看一下涉及到的几个属性对象在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory以及org.springframework.beans.factory.support.AbstractBeanFactory中。

 1 /** Cache of singleton objects: bean name to bean instance. */
 2 /** 已初始化完成的单例bean,key为beanName,value为bean实例 **/
 3 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
 4 
 5 /** Cache of singleton factories: bean name to ObjectFactory. */
 6 /** 未初始化完成的bean,key为beanName,value为创建bean实例的方法**/
 7 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
 8 
 9 /** Cache of early singleton objects: bean name to bean instance. */
10 /** 未初始化完成的bean,key为beanName,value为bean实例**/
11 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
12 
13 /** Names of beans that are currently in creation. */
14 /** 正在创建的单例bean的name **/
15 private final Set<String> singletonsCurrentlyInCreation =
16       Collections.newSetFromMap(new ConcurrentHashMap<>(16));
17 
18 /** Names of beans that are currently in creation. */
19 /** 正在创建的prototype bean的name **/
20 private final ThreadLocal<Object> prototypesCurrentlyInCreation =
21       new NamedThreadLocal<>("Prototype beans currently in creation");:

  首先是获取bean的方法:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean()方法:

 1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
 2       throws BeanCreationException {
 3 
 4    // Instantiate the bean.
 5    BeanWrapper instanceWrapper = null;
 6    if (mbd.isSingleton()) {
 7       instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
 8    }
 9    if (instanceWrapper == null) {
10        // 具体创建bean实例的方法
11       instanceWrapper = createBeanInstance(beanName, mbd, args);
12    }
13    final Object bean = instanceWrapper.getWrappedInstance();
14    Class<?> beanType = instanceWrapper.getWrappedClass();
15    // 部分代码省略
16    // Eagerly cache singletons to be able to resolve circular references
17    // even when triggered by lifecycle interfaces like BeanFactoryAware.
18    // 如果bean是单例&&允许重复引用(默认为true)&& 当前bean正在创建中
19    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
20          isSingletonCurrentlyInCreation(beanName));
21    if (earlySingletonExposure) {
22       // 将bean添加到singletonFactories中
23       addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
24    }
25 
26    // Initialize the bean instance.
27    Object exposedObject = bean;
28    try {
29        // 计算bean的依赖,其作用是将依赖的bean注入到当前bean中(不存在则创建)
30       populateBean(beanName, mbd, instanceWrapper);
31       // 初始化当前bean中的其他属性值
32       exposedObject = initializeBean(beanName, exposedObject, mbd);
33    }
34    catch (Throwable ex) {
35       if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
36          throw (BeanCreationException) ex;
37       }
38       else {
39          throw new BeanCreationException(
40                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
41       }
42    }
43    // 省略部分代码
44    return exposedObject;
45 }

  创建bean实例的方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance()方法:

 1 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
 2    // Make sure bean class is actually resolved at this point.
 3    Class<?> beanClass = resolveBeanClass(mbd, beanName);
 4     // 省略部分代码
 5 
 6    // Shortcut when re-creating the same bean...
 7    boolean resolved = false;
 8    boolean autowireNecessary = false;
 9    if (args == null) {
10       synchronized (mbd.constructorArgumentLock) {
11          if (mbd.resolvedConstructorOrFactoryMethod != null) {
12             resolved = true;
13             autowireNecessary = mbd.constructorArgumentsResolved;
14          }
15       }
16    }
17    if (resolved) {
18       if (autowireNecessary) {
19           /** 
20           bean没有无参构造函数时使用此方法实例化,
21           如果构造函数中有依赖的bean,则创建此bean并注入
22           返回实例化后的bean
23           **/
24          return autowireConstructor(beanName, mbd, null, null);
25       }
26       else {
27           /**
28            使用无参的构造函数时使用此方法实例化
29            返回实例化后的bean
30            **/
31          return instantiateBean(beanName, mbd);
32       }
33    }
34 
35    // Candidate constructors for autowiring?
36    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
37    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
38          mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
39       return autowireConstructor(beanName, mbd, ctors, args);
40    }
41 
42    // Preferred constructors for default construction?
43    ctors = mbd.getPreferredConstructors();
44    if (ctors != null) {
45       return autowireConstructor(beanName, mbd, ctors, null);
46    }
47 
48    // No special handling: simply use no-arg constructor.
49    return instantiateBean(beanName, mbd);
50 }

  将上面的代码转换成流程图,获取bean的主要流程图如下:

  创建bean的主要流程图如下:

 

  经过上面的分析之后我们知道,在获取单例bean时会先从缓存中获取bean,获取到了则返回,未获取到才创建。在创建bean时,如果是单例bean,则他会在注入依赖之前先将自己未初始化的bean存入到缓存中。经过上面两步,循环依赖就解决了。

现在来分析一下一些结论:

  1. 为什么bean都是非单例就不行?

  原因已经显而易见了,因为只有单例bean才会将其放入缓存中。

  2. 构造器注入跟setter注入的区别?

  setter注入是先创建完bean,然后将bean放入缓存,最后注入依赖;而构造器注入是在创建bean之前先获取依赖,如果依赖没有在缓存中或者创建,则创建依赖bean,依赖bean又会去创建当前bean,所以失败。

  3. 为什么懒加载会影响循环依赖的结果?

  循环依赖的根本问题其实就是加载顺序的问题,比如类A是单例懒加载,类B是prototype立即加载,都采用setter注入。那么启动会报错,因为创建B需要A,因为A懒加载所以缓存中不存在,需要新建,创建A又需要B,因为B不是单例,所以缓存中不存在B,B也会新建,产生了循环依赖问题。

  而如果类B也是懒加载的话,如果你先获取B则会报错,先获取A则不会报错,这就是加载顺序的问题。而懒加载就会影响到加载顺序。

原文地址:https://www.cnblogs.com/ouhaitao/p/11850893.html