Spring如何解决循环依赖的

Spring如何解决循环依赖的

1.什么是循环依赖?

循环依赖指的是循环引用,TestA对象引用了TestB,TestB对象引用了TestA。引用形成环。

2.spring如何解决循环依赖的?

spring容器循环依赖包括构造器循环依赖和setter循环依赖。

首先看spring如何处理构造器循环依赖的。

构造器循环依赖示例代码

@Component
public class ClassA {
    private ClassB classB;
    public ClassA(ClassB classB) {
        this.classB = classB;
    }
}
@Component
public class ClassB {
  private ClassA classA;
  public ClassB(ClassA classA){
      this.classA = classA;
  }
}

假如spring容器先创建TestA对象,容器首先查询TestA对象的可用的构造函数。这里就是 ClassA(ClassB classB),需要引用TestB的实例。spring容器查询TestB对象是否已经创建,如果没有,则会创建TestB对象,spring容器在创建bean的时候是有条件判断的:

DefaultSingletonBeanRegistry类中
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         ...
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         ...
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
          ....
         }
         catch (BeanCreationException ex) {
            ....
         }
         finally {
           ....
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}
protected void afterSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
      throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
   }
}

spring 在创建classA之前会将TestA的beanName(classA)添加到singletonsCurrentlyInCreation的Set中,如果添加成功,则说明这个bean进入inCreation状态。如果classA创建成功 在afterSingletonCreation中从 singletonsCurrentlyInCreation移除classA。classA依赖classB,容器对classB执行getSingleton()方法执行beforeSingletonCreation校验后,到这里都不会出现错误。在singletonFactory.getObject() 真正创建classB的时候,又会发现classB的创建依赖classA,这是正在创建classA时,beforeSingletonCreation校验singletonsCurrentlyInCreation.add()返回false。创建失败,抛出BeanCurrentlyInCreationException!
结论:构造器注入的循环依赖,spring无法解决。

setter循环依赖

@Component
public class ClassA {
    @Autowired
    private ClassB classB;
}
@Component
public class ClassB {
    @Autowired
    private ClassA classA;
}

setter循环依赖spring是如何处理的?
先看看spring创建bean的时候大致的调用过程

AbstractBeanFactory
protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {  
       ....
   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   	if (sharedInstance != null && args == null) {
       	....
   	    	beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   	}else{
      ....
         // Create bean instance.
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  //创建bean
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                ....
               }
            });
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
          ...
          //bean是prototype的
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
           }
         }
         else {
           ...
      }
      catch (BeansException ex) {
       ...
      }
      finally {
         beanCreation.end();
      }
   }
   return adaptBeanInstance(name, beanInstance, requiredType);
}
DefaultSingletonBeanRegistry中
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Quick check for existing instance without full singleton lock
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

调用3
AbstractAutowireCapableBeanFactory
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   // Instantiate the bean.
    ...... 
   if (instanceWrapper == null) {
       //创建根据无参构造函数 创建bean  @1
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
  .... 
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
      if (logger.isTraceEnabled()) {
         logger.trace("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }
   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      populateBean(beanName, mbd, instanceWrapper);
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
     ......
   }
    ......

   // Register bean as disposable.
   try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }
   return exposedObject;
}

DefaultSingletonBeanRegistry

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);
      }
   }
}

假设spring先创建classA。以下是spring创建classA的主要过程:

  1. spring在执行classA创建的时候 调用 doGetBean(),先判断 Object sharedInstance = getSingleton(beanName); 中是否有bean存在。
  2. 当sharedInstance=null 执行createBean逻辑创建bean。执行doCreateBean 执行@1处 createBeanInstance 创建bean ; 当sharedInstance!=null从getObjectForBeanInstance中获取;
  3. 判断classA bean earlySingletonExposure是否为true,这里显然为true
  4. 执行addSingletonFactory,将bean放在ObjectFactory中,并将该factory放入singletonFactories中。
  5. 执行 populateBean(beanName, mbd, instanceWrapper);是setter classB属性,此时创建classB。重复1,2,3,4步骤
  6. classB在setter classA的时候执行步骤1,获取到classA关联的ObjectFactory,获取 singletonObject。
  7. 完成classB的populateBean()
  8. 完成classA的populateBean()
    classA与classB都成功创建

结论:setter注入的循环依赖,spring可以解决。

prototy作用域下的classA,classB循环依赖处理。

在判断 earlySingletonExposure属性的时候,前提是 mbd.isSingleton()为true。所以不能提前暴露bean对应的ObjectFactory,进而提前暴露bean。所以不能解决prototype作用域下的循环引用。试想一下,prototype是每次getbean容器都会创建一个bean的实例。所以不能提前缓存bean的创建。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值