springIoc依赖注入循环依赖三级缓存实践

 更新时间:2026年06月05日 08:48:21   作者:bingbingYang_88  
这篇文章主要介绍了springIoc依赖注入循环依赖三级缓存实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

springIoc的理解,原理和实现

控制反转

理论思想,原来的对象是由使用者来进行控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理

依赖注入DI

依赖注入,把对应的属性的值注入到具体的对象中,@autowired,populateBean完成属性的注入

容器

beanFactory,存储对象,使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象,earylySingletonObject,factoryObject,整个bean的生命周期,从创建初始化使用到销毁的过程都是容器来管理的

分:

  1. 一般ioc容器的时候涉及到容器的创建过程(beanFactory,DefaultListableBeanFactory),向bean工厂中设置一些参数BeanPostProcessor,Aware接口的子类等等属性
  2. 加载解析bean对象,准备要创建的bean对象的定义对象 beanDefinition(xml或者注解的解析过程)
  3. beanFactoryPostProcessor的处理,此处是扩展点,PlaceHolder ConfigurSupport(占位符),ConfigurationClassProcessor.
  4. BeanPostProcessor的注册功能,方便后续bean对象完成具体的扩展对象。
  5. 通过反射的方式将BeanDefinition对象实例化成具体的bean对象。
  6. bean对象的初始化过程(填充属性,调用aware的子类方法,调用BeanPostProcessor前置处理方法,调用init-method方法,BeanPostProcessor的后置处理方法)
  7. 生成完整的bean对象,通过getBean方法可以直接获取。

createBeanFactory,getBean,doGetBean,createBean,doCreateBean,createBeanInstance,populateBean

  1. 先通过createBeanFactory创建出一个Bean工厂(DeafaultListableBeanFactory)
  2. 开始循环创建对象,因为容器中的bean默认都是单例的,所以通过getBean,doGetBean从容器中查找,找不到的话,通过createBean,doCreateBean方法,以反射的方式创建对象,一般情况下使用无参的构造方法(getDeclaredConstruce,newInstance)
  3. 进行对象的属性填充populateBean
  4. 进行其他的初始化操作initializingBean

描述一下bean的生命周期

  1. 实例化bean,反射的方式生成对象
  2. 填充bean的属性:populateBean(),循环依赖的问题(三级缓存)
  3. 调用aware接口相关的方法:invokeAwareMethod(完成beanName可以获取容器bean的名称,BeanFactory获取当前bean factory这也可以调用容器的服务,BeanClassLoader对象的属性设置)
  4. 调用BeanPostProcessor中的前置方法:使用比较多的ApplicationContextPostProcessor设置ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver等对象。
  5. 调用initmethod方法:invokeInitmethod(),判断是否实现了IntialzingBean接口,如果有,调用afterPropertiesSet方法。
  6. 调用BeanPostProceessor的后置处理方法:spring的aop就是在此实现的,AbstractAutoProxyCreator注册Destuction相关的回调接口。
  7. 通过getbean获取完整对象
  8. 销毁 判断是否实现了DisposableBean接口 destroyMethod方法

循环依赖

什么是循环依赖

第一种互相依赖:A 依赖 B,B 又依赖 A,它们之间形成了循环依赖

第二种三者之间的依赖 A依赖B,B依赖C,C依赖A

第三种是自我依赖:A依赖A形成了循环依赖

三级缓存

  1. singletonObjects:缓存某个beanName对应的经过了完整生命周期的bean
  2. earlySingletonObjects:缓存提前拿原始对象进行了AOP之后得到的代理对象,原始对象还没有进行属性注入和后续的BeanPostProcessor等生命周期
  3. singletonFactories:缓存的是一个ObjectFactory,主要用来去生成原始对象进行了AOP之后得到的代理对象,在每个Bean的生成过程中,都会提前暴露一个工厂,这个工厂可能用到,也可能用不到,如果没有出现循环依赖依赖本bean,那么这个工厂无用,本bean按照自己的生命周期执行,执行完后直接把本bean放入singletonObjects中即可,如果出现了循环依赖依赖了本bean,则另外那个bean执行ObjectFactory提交得到一个AOP之后的代理对象(如果有AOP的话,如果无需AOP,则直接得到一个原始对象)。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	/** Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

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

	/** Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
}

能否把一级缓存和二级缓存合并,只保留一个map结构来完成类似的功能?

理论上是可行的,一级缓存和二级缓存的value类型都是Object,都可以用来存放对象,只是对象的状态不同而已,所以当使用一个map的时候,只要给定具体的标识就可以解决这个问题,也就是说设置对象的时候,在value中不再直接存放对象,而是对象加标识位,比如0代表成品,1代表半成品,那么一个map就可以存储成品对象和半成品对象了,但是虽然可以这么干,没人会这么做,代码不优雅,而且每次在进行对象的存或者放的时候都要判断是否是成品对象,比较麻烦,直接用两个map结构解决即可

如果只有一级缓存和二级缓存,能否解决循环依赖的问题?

可以,但是有前提条件:没有aop的配置或者不需要创建代理对象的时候,两个map就可以解决循环依赖的问题

为什么三级缓存可以解决aop下的循环依赖问题?三级缓存到底有什么作用?

1,在同一个容器中,能否出现同名的不同对象?

不能,id是唯一标识

2,在同一个容器中,按照标准的生命周期,先创建了原始对象,后续又创建了代理对象,那时会怎么办?

当创建了代理对象之后,应该要使用代理对象的,但是原始对象已经存在,那么应该将原始对象给覆盖掉。getEarlyBeanReference()方法执行的逻辑是一样的

3,三级缓存到底有什么作用,为什么存在代理对象的时候就要使用三级缓存呢?

在标准的bean的生命周期中,要先创建出原始对象,创建出原始对象之后要使用populateBean方法来完成属性的赋值,此时赋值的对象是原始对象,因为代理对象还没有创建,代理对象的创建步骤是在BeanPostProcessor的后置处理方法中,也就是说已经完成赋值之后代理对象才创建出来,所以会报错(this means that said other beans do not use the final version of the bean),如何解决这个问题呢?

需要将代理对象的创建前置,也就是说在对象赋值的那一刻,要唯一性的确定出到底是原始对象还是代理对象,所以会优先把所有的bean都放到三级缓存中,在需要进行对象赋值的时候,从三级缓存中取出lambda表达式,lambda表达式的执行逻辑就是确定原始对象还是代理对象。如果是原始对象就赋值原始对象,如果是代理对象就赋值代理对象。

Spring中哪些情况下,不能解决循环依赖问题?

1,多例Bean通过setter注入的情况,不能解决循环依赖的问题。当两个多例Bean相互依赖并且使用 Setter 方法注入时,Spring容器无法解决循环依赖。这是因为在多例模式下,每次请求获取一个新的Bean实例,Spring容器无法在创建Bean之前就确定依赖关系。

2,构造器注入的bean情况,不能解决循环依赖的问题。循环依赖的产生:循环依赖通常在Bean的创建阶段发生,而构造器注入是在Bean创建之前发生的,因此无法通过构造器注入的方式解决已经发生的循环依赖。

3,设置了@DependsOn的Bean情况,不能解决循环依赖的问题。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring定义Bean范围的三种方式

    Spring定义Bean范围的三种方式

    在Spring框架中,Bean的作用域(scope)决定了一个Bean实例的生命周期和可见性,Spring支持多种作用域,最常用的是singleton和prototype,此外还有request、session等Web应用相关的特定作用域,本文给大家介绍了Spring定义Bean范围的三种方式,需要的朋友可以参考下
    2024-08-08
  • Java序列化机制与原理的深入分析

    Java序列化机制与原理的深入分析

    有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍
    2013-05-05
  • Java线程队列LinkedBlockingQueue的使用

    Java线程队列LinkedBlockingQueue的使用

    本文主要介绍了Java线程队列LinkedBlockingQueue的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • 解析Mybatis延迟加载问题

    解析Mybatis延迟加载问题

    这篇文章主要介绍了Mybatis的延迟加载问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-05-05
  • springBoot中观察者模式详解

    springBoot中观察者模式详解

    观察者模式增强应用的灵活性和可扩展性,利用java.util.Observable和java.util.Observer实现,Spring通过ApplicationEvent类和事件广播器管理事件,支持应用上下文和请求相关的事件处理,实现松耦合和动态通知,优点包括松耦合、动态通知、易于扩展
    2024-11-11
  • 详解关于mybatis-plus中Service和Mapper的分析

    详解关于mybatis-plus中Service和Mapper的分析

    这篇文章主要介绍了详解关于mybatis-plus中Service和Mapper的分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Spring Bean实例化实现过程解析

    Spring Bean实例化实现过程解析

    这篇文章主要介绍了Spring Bean实例化实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • java:程序包javax.servlet.http不存在问题解决

    java:程序包javax.servlet.http不存在问题解决

    这篇文章主要给大家介绍了关于java:程序包javax.servlet.http不存在问题解决的相关资料,如果引用的包依赖的库文件缺失或版本不匹配,就会导致"Java 程序包不存在"的错误,需要的朋友可以参考下
    2023-10-10
  • Spring国际化和Validation详解

    Spring国际化和Validation详解

    本文介绍了SpringBoot中国际化和Validation的融合实现,包括配置MessageSource和LocalValidatorFactoryBean,以及自定义约束注解和校验器,通过解析请求头中的Accept-Language,SpringBoot可以返回不同语言的文本信息
    2024-11-11
  • Redis与session使用及说明

    Redis与session使用及说明

    文章介绍了传统Session和Redis在分布式场景下存储Session的优缺点对比,指出Redis更适合替代传统Session,因为它提供了分布式共享、高效存储、持久化保障等优势
    2026-02-02

最新评论