zoukankan      html  css  js  c++  java
  • 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则不会报错,这就是加载顺序的问题。而懒加载就会影响到加载顺序。

  • 相关阅读:
    JDBC数据库访问操作的动态监测 之 p6spy
    ZeroC Ice启用SSL通讯的配置
    heartbeat在yum系发行版本的处理资料
    VisualStudio 调试Linux
    JVM之上的语言小集
    程序人生【一些经典的资料】
    读史知今、以史为鉴 【技术商业化】
    ipython notebook 浏览器中编写数学公式和现实
    大数据 云计算 等搜集的资料
    GO 1.5 代码编译安装 [centos7 64位]
  • 原文地址:https://www.cnblogs.com/ouhaitao/p/11850893.html
Copyright © 2011-2022 走看看