spring 循环依赖与三级缓存

简介: spring 循环依赖与三级缓存

当有两个类A、B相互依赖时便会形成循环依赖,多个类之间相互依赖也会存在循环依赖。

@Service
public class ServiceA {
  @Autowired
  private ServiceB serviceB;

  public String say(){
    return "hello";
  }
}

@Service
public class ServiceB {

  @Autowired
  private ServiceA serviceA;

}

当构造方法注入依赖时循环无解,会有如下提示

The dependencies of some of the beans in the application context form a cycle:

   cycleController (field com.paw.cycle.dependency.service.ServiceA com.paw.cycle.dependency.controller.CycleController.serviceA)
┌─────┐
|  serviceA defined in file [/Users/.../target/classes/com/paw/cycle/dependency/service/ServiceA.class]
↑     ↓
|  serviceB defined in file [/Users/.../target/classes/com/paw/cycle/dependency/service/ServiceB.class]
└─────┘

看下spring是如何解决循环依赖的

开启日志

logging:
  level:
    org.springframework: trace

运行查看日志

main] o.s.b.f.s.DefaultListableBeanFactory     : Finished creating instance of bean 'cycleDependencyApplication'
main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory'
main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'cycleController'
main] o.s.b.f.s.DefaultListableBeanFactory     : Creating instance of bean 'cycleController'
main] o.s.b.f.s.DefaultListableBeanFactory     : Eagerly caching bean 'cycleController' to allow for resolving potential circular references
main] o.s.b.f.s.DefaultListableBeanFactory     : Finished creating instance of bean 'cycleController'
main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'serviceA'
main] o.s.b.f.s.DefaultListableBeanFactory     : Creating instance of bean 'serviceA'
main] o.s.b.f.annotation.InjectionMetadata     : Registered injected element on class [com.paw.cycle.dependency.service.ServiceA]: AutowiredFieldElement for private com.paw.cycle.dependency.service.ServiceB com.paw.cycle.dependency.service.ServiceA.serviceB
main] o.s.b.f.s.DefaultListableBeanFactory     : Eagerly caching bean 'serviceA' to allow for resolving potential circular references
main] o.s.b.f.annotation.InjectionMetadata     : Processing injected element of bean 'serviceA': AutowiredFieldElement for private com.paw.cycle.dependency.service.ServiceB com.paw.cycle.dependency.service.ServiceA.serviceB
main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'serviceB'
main] o.s.b.f.s.DefaultListableBeanFactory     : Creating instance of bean 'serviceB'
main] o.s.b.f.annotation.InjectionMetadata     : Registered injected element on class [com.paw.cycle.dependency.service.ServiceB]: AutowiredFieldElement for private com.paw.cycle.dependency.service.ServiceA com.paw.cycle.dependency.service.ServiceB.serviceA
main] o.s.b.f.s.DefaultListableBeanFactory     : Eagerly caching bean 'serviceB' to allow for resolving potential circular references
main] o.s.b.f.annotation.InjectionMetadata     : Processing injected element of bean 'serviceB': AutowiredFieldElement for private com.paw.cycle.dependency.service.ServiceA com.paw.cycle.dependency.service.ServiceB.serviceA
main] o.s.b.f.s.DefaultListableBeanFactory     : Returning eagerly cached instance of singleton bean 'serviceA' that is not fully initialized yet - a consequence of a circular reference
main] f.a.AutowiredAnnotationBeanPostProcessor : Autowiring by type from bean name 'serviceB' to bean named 'serviceA'
main] o.s.b.f.s.DefaultListableBeanFactory     : Finished creating instance of bean 'serviceB'
main] f.a.AutowiredAnnotationBeanPostProcessor : Autowiring by type from bean name 'serviceA' to bean named 'serviceB'
main] o.s.b.f.s.DefaultListableBeanFactory     : Finished creating instance of bean 'serviceA'
main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of sinleton bean 'serviceB'    

可以梳理到基本流程:

创建ing serviceA==>需要注入serviceB==>缓存半成品serviceA ==>创建ing serviceB==>需要注入serviceA==>缓存半成品serviceB==>注入缓存的半成品 serviceA==>完成创建serviceB==>service 注入serviceB ==>完成serviceA创建。

DefaultSingletonBeanRegistry的三级缓存

// 一级实例化好的bean
/**Cache of singleton objects: bean name to bean instance.*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 二级半成品  未进行属性注入
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

// 三级 生成bean的ObjectFactory
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

获取bean实例对象

先从一级取 》再从二级取 》最后从三级取

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 一级缓存
 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;
}

加入条件断点,开始顺腾摸瓜

beanName.equals("serviceA")

image081301.png

类的继承关系

SimpleAliasRegistry (org.springframework.core)

|-DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)

|-|-FactoryBeanRegistrySupport (org.springframework.beans.factory.support)

|-|-|-AbstractBeanFactory (org.springframework.beans.factory.support)

|-|-|-|-AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)

|-|-|-|-|-DefaultListableBeanFactory (org.springframework.beans.factory.support)

|-|-|-|-|-XmlBeanFactory (org.springframework.beans.factory.xml)

三级缓存objectFactory 通过匿名内部类实现 (匿名类 调用了 AbstractAutowireCapableBeanFactory#getEarlyBeanReference方法) getEarlyBeanReference 获取早期的半成品对象。

AbstractAutowireCapableBeanFactory
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  throws BeanCreationException {
      ...
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    ...
}

singletonFactory AbstractAutowireCapableBeanFactory

// 加入三级缓存
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);
  }
 }
}

// 由ObjectFactory创建bean

AbstractBeanFactory#doGetBean
// 创建bean实例
sharedInstance = getSingleton(beanName, () -> {
 try {
  return createBean(beanName, mbd, args);
 }
 ...
 }

==>  DefaultSingletonBeanRegistry#getSingleton
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) {
   if (this.singletonsCurrentlyInDestruction) {
    throw new BeanCreationNotAllowedException(beanName,
      "Singleton bean creation not allowed while singletons of this factory are in destruction " +
      "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
   }
   if (logger.isDebugEnabled()) {
    logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
   }
   // 创建bean之前的处理
   beforeSingletonCreation(beanName);
   boolean newSingleton = false;
   boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
   if (recordSuppressedExceptions) {
    this.suppressedExceptions = new LinkedHashSet<>();
   }
   try {
       // 通过三级缓存的objectFactory获取bean对象实例
    singletonObject = singletonFactory.getObject();
    newSingleton = true;
   }
   catch (IllegalStateException ex) {
    // Has the singleton object implicitly appeared in the meantime ->
    // if yes, proceed with it since the exception indicates that state.
    singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null) {
     throw ex;
    }
   }
   catch (BeanCreationException ex) {
    if (recordSuppressedExceptions) {
     for (Exception suppressedException : this.suppressedExceptions) {
      ex.addRelatedCause(suppressedException);
     }
    }
    throw ex;
   }
   finally {
    if (recordSuppressedExceptions) {
     this.suppressedExceptions = null;
    }
    // 创建完后的处理
    afterSingletonCreation(beanName);
   }
   if (newSingleton) {
       // 创建成功添加到一级缓存
    addSingleton(beanName, singletonObject);
   }
  }
  return singletonObject;
 }

AbstractAutowireCapableBeanFactory 创建bean

添加到三级缓存==>创建Eagerly caching bean ===>注入bean属性实例化bean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  throws BeanCreationException {

 // Instantiate the bean.
 BeanWrapper instanceWrapper = null;
 if (mbd.isSingleton()) {
  instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
 }
 if (instanceWrapper == null) {
  instanceWrapper = createBeanInstance(beanName, mbd, args);
 }
 final Object bean = instanceWrapper.getWrappedInstance();
 Class<?> beanType = instanceWrapper.getWrappedClass();
 if (beanType != NullBean.class) {
  mbd.resolvedTargetType = beanType;
 }

 // Allow post-processors to modify the merged bean definition.
 synchronized (mbd.postProcessingLock) {
  if (!mbd.postProcessed) {
   try {
    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
   }
   catch (Throwable ex) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
      "Post-processing of merged bean definition failed", ex);
   }
   mbd.postProcessed = true;
  }
 }

 // Eagerly cache singletons to be able to resolve circular references
 // even when triggered by lifecycle interfaces like BeanFactoryAware.
 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");
  }
  // 添加三级缓存 beanFactory
  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
 }

 // Initialize the bean instance.
 Object exposedObject = bean;
 try {
 // 填充bean属性 即注入@Autowired字段
  populateBean(beanName, mbd, instanceWrapper);
  exposedObject = initializeBean(beanName, exposedObject, mbd);
 }
 catch (Throwable ex) {
  if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
   throw (BeanCreationException) ex;
  }
  else {
   throw new BeanCreationException(
     mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
  }
 }

 if (earlySingletonExposure) {
  Object earlySingletonReference = getSingleton(beanName, false);
  if (earlySingletonReference != null) {
   if (exposedObject == bean) {
    exposedObject = earlySingletonReference;
   }
   else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    String[] dependentBeans = getDependentBeans(beanName);
    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
    for (String dependentBean : dependentBeans) {
     if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
      actualDependentBeans.add(dependentBean);
     }
    }
    if (!actualDependentBeans.isEmpty()) {
     throw new BeanCurrentlyInCreationException(beanName,
       "Bean with name '" + beanName + "' has been injected into other beans [" +
       StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
       "] in its raw version as part of a circular reference, but has eventually been " +
       "wrapped. This means that said other beans do not use the final version of the " +
       "bean. This is often the result of over-eager type matching - consider using " +
       "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
    }
   }
  }
 }

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

 return exposedObject;
}

属性注入serviceB

填充属性

//AbstractAutowireCapableBeanFactory
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 

AbstractAutowireCapableBeanFactory#postProcessProperties

InjectionMetadata类进行属性注入

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
 try {
  metadata.inject(bean, beanName, pvs);
 }
 catch (BeanCreationException ex) {
  throw ex;
 }
 catch (Throwable ex) {
  throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
 }
 return pvs;
}

存在AOP的情况singletonObject = singletonFactory.getObject(); 多次调用会生成新的代理对象,(不同代理对象代理的还是同一个bean对象serviceA)。spring 将singletonObject 代理对象放入到二级缓存,注入到serviceB中的也是代理对象singletonObject。

如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象。

总结:

spring中三级缓存存放ObjectFactory(匿名类 调用了 AbstractAutowireCapableBeanFactory #getEarlyBeanReference方法),通过getObect获取半成品对象放入二级缓存,完成属性注入及bean初始化后放入一级缓存。对存在AOP代理的情况,三级缓存每次会生成一个新的代理对象,因此将getObject生成的代理对象singletonObject放入到二级缓存,完成属性注入后,将代理对象添加到一级缓存。

spring-boot 2.6.0中对循环依赖默认报错,需手动开启。

相关文章
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
1月前
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
26天前
|
存储 XML 缓存
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(一)
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南
60 0
|
6天前
|
存储 缓存 Java
Spring解决循环依赖
Spring解决循环依赖
|
23天前
|
缓存 算法 Java
开发必懂的Spring循环依赖图解 Spring 循环依赖
开发必懂的Spring循环依赖图解 Spring 循环依赖
18 1
|
26天前
|
缓存 算法 Java
Spring解决循环依赖
Spring解决循环依赖
19 0
|
1月前
|
缓存 NoSQL Java
spring cache整合redis实现springboot项目中的缓存功能
spring cache整合redis实现springboot项目中的缓存功能
46 1
|
1月前
|
Java 开发者 Spring
【Java】Spring循环依赖:原因与解决方法
【Java】Spring循环依赖:原因与解决方法
37 0
|
1月前
|
Java 数据库连接 Spring
Spring Boot 3.2.2整合MyBatis-Plus 3.5.5依赖不兼容问题
Spring Boot 3.2.2整合MyBatis-Plus 3.5.5依赖不兼容问题
45 0
|
1月前
|
消息中间件 运维 监控