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中对循环依赖默认报错,需手动开启。

相关文章
|
5天前
|
缓存 架构师 Java
图解 Spring 循环依赖,一文吃透!
Spring 循环依赖如何解决,是大厂面试高频,本文详细解析,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
图解 Spring 循环依赖,一文吃透!
|
18天前
|
存储 缓存 Java
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
58 2
|
2月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
189 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
1月前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
31 1
|
2月前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
40 4
|
2月前
|
存储 缓存 Java
在Spring Boot中使用缓存的技术解析
通过利用Spring Boot中的缓存支持,开发者可以轻松地实现高效和可扩展的缓存策略,进而提升应用的性能和用户体验。Spring Boot的声明式缓存抽象和对多种缓存技术的支持,使得集成和使用缓存变得前所未有的简单。无论是在开发新应用还是优化现有应用,合理地使用缓存都是提高性能的有效手段。
39 1
|
3月前
|
存储 缓存 Java
面试问Spring循环依赖?今天通过代码调试让你记住
该文章讨论了Spring框架中循环依赖的概念,并通过代码示例帮助读者理解这一概念。
面试问Spring循环依赖?今天通过代码调试让你记住
|
3月前
|
缓存 NoSQL Java
SpringBoot的三种缓存技术(Spring Cache、Layering Cache 框架、Alibaba JetCache 框架)
Spring Cache 是 Spring 提供的简易缓存方案,支持本地与 Redis 缓存。通过添加 `spring-boot-starter-data-redis` 和 `spring-boot-starter-cache` 依赖,并使用 `@EnableCaching` 开启缓存功能。JetCache 由阿里开源,功能更丰富,支持多级缓存和异步 API,通过引入 `jetcache-starter-redis` 依赖并配置 YAML 文件启用。Layering Cache 则提供分层缓存机制,需引入 `layering-cache-starter` 依赖并使用特定注解实现缓存逻辑。
974 1
SpringBoot的三种缓存技术(Spring Cache、Layering Cache 框架、Alibaba JetCache 框架)
|
3月前
|
缓存 Java Spring
spring如何解决循环依赖
Spring框架处理循环依赖分为构造器循环依赖与setter循环依赖两种情况。构造器循环依赖不可解决,Spring会在检测到此类依赖时抛出`BeanCurrentlyInCreationException`异常。setter循环依赖则通过缓存机制解决:利用三级缓存系统,其中一级缓存`singletonObjects`存放已完成的单例Bean;二级缓存`earlySingletonObjects`存放实例化但未完成属性注入的Bean;三级缓存`singletonFactories`存放创建这些半成品Bean的工厂。
|
3月前
|
缓存 Java Spring
Spring缓存实践指南:从入门到精通的全方位攻略!
【8月更文挑战第31天】在现代Web应用开发中,性能优化至关重要。Spring框架提供的缓存机制可以帮助开发者轻松实现数据缓存,提升应用响应速度并减少服务器负载。通过简单的配置和注解,如`@Cacheable`、`@CachePut`和`@CacheEvict`,可以将缓存功能无缝集成到Spring应用中。例如,在配置文件中启用缓存支持并通过`@Cacheable`注解标记方法即可实现缓存。此外,合理设计缓存策略也很重要,需考虑数据变动频率及缓存大小等因素。总之,Spring缓存机制为提升应用性能提供了一种简便快捷的方式。
50 0