当前位置: 首页 > news >正文

Spring之【循环引用】

目录

前置知识

        SingletonBeanRegistry

        DefaultSingletonBeanRegistry

Spring中处理循环引用的流程分析

        定义两个具有循环引用特点的Bean

        执行A的实例化

        执行A的属性填充(执行过程中发现A依赖B,就去执行B的实例化逻辑)

        执行B的实例化

        执行B的属性填充

        执行B的初始化

        执行A的属性填充(此时依赖的B已经完成了实例化和初始化放到容器的单例池中,接着执行之前没有执行完成的A的属性填充逻辑)

        执行A的初始化


前置知识

SingletonBeanRegistry

该接口中定义了一些和单例Bean有关的方法

package org.springframework.beans.factory.config;public interface SingletonBeanRegistry {/*** 往容器中添加单例bean对象*/void registerSingleton(String beanName, Object singletonObject);/*** 通过bean名字获取bean对象*/Object getSingleton(String beanName);/*** 判断容器中是否包含某bean名字的单例bean*/boolean containsSingleton(String beanName);/*** 获取容器中所有单例bean的名称集合*/String[] getSingletonNames();/*** 获取容器中单例bean对象的数量*/int getSingletonCount();
}

DefaultSingletonBeanRegistry

  • 定义了三个Map集合(也就是常说的三级缓存)
  • 定义了一个Set集合,用于存储正在创建的单例Bean的beanName
  • 对SingletonBeanRegistry接口提供方法的实现
package org.springframework.beans.factory.support;public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {// 一级缓存private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 三级缓存private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 二级缓存private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// ...// 正在创建的单例Bean的beanNameprivate final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));/*** 对registerSingleton方法的实现*/@Overridepublic void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {// ...synchronized (this.singletonObjects) {// 通过beanName先从一级缓存中获取Object oldObject = this.singletonObjects.get(beanName);// 一级缓存中已经有该beanName的对象,就抛异常if (oldObject != null) {throw new IllegalStateException("Could not register object [" + singletonObject +"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");}// 一级缓存中没有该beanName的对象,就执行添加逻辑addSingleton(beanName, singletonObject);}}/*** 往容器中添加Bean*/protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {// beanName作为key,bean对象作为value,往一级缓存中添加this.singletonObjects.put(beanName, singletonObject);// 删除三级缓存中key为beanName的节点this.singletonFactories.remove(beanName);// 删除二级缓存中key为beanName的节点this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}// .../*** 对getSingleton方法的实现(通过beanName获取bean对象)*/    @Override@Nullablepublic Object getSingleton(String beanName) {// 调用重载方法return getSingleton(beanName, true);}/*** getSingleton第二个参数是boolean类型的重载方法*/@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// 先从一级缓存中获取bean对象Object singletonObject = this.singletonObjects.get(beanName);// 一级缓存中没有该beanName对应的对象并且该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) {// 执行三级缓存中的Lambda表达式的逻辑singletonObject = singletonFactory.getObject();// 放入二级缓存this.earlySingletonObjects.put(beanName, singletonObject);// 删除三级缓存中key为beanName的节点this.singletonFactories.remove(beanName);}}}}// 返回bean对象return singletonObject;}/*** getSingleton的重载方法* 第二个参数为Lambda表达式,为bean的创建过程*/public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {// ...synchronized (this.singletonObjects) {// 先从一级缓存中获取bean对象Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {// bean正在被创建,抛异常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!)");}// ...// 创建bean之前,做一个标记,标记该beanName的bean正在创建中beforeSingletonCreation(beanName);boolean newSingleton = false;// ...try {// 执行Lambda的逻辑,执行bean的实例化和初始化流程singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// ...}catch (BeanCreationException ex) {// ...}finally {// ...// 移除该beanName正在创建对象的标识afterSingletonCreation(beanName);}if (newSingleton) {// 将完成实例化和初始化的bean对象放入单例池中addSingleton(beanName, singletonObject);}}// 返回bean对象return singletonObject;}}
}

Spring中处理循环引用的流程分析

定义两个具有循环引用特点的Bean

package spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** A依赖B*/
@Component
public class A {@Autowiredprivate B b;
}
package spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** B依赖A*/
@Component
public class B {@Autowiredprivate A a;
}

执行A的实例化

一、DefaultListableBeanFactory#preInstantiateSingletons

遍历beanNames,根据beanName实例化非懒加载的单例Bean

二、AbstractBeanFactory#getBean

getBean - doGetBean

三、AbstractBeanFactory#doGetBean

先尝试从容器中获取,有就直接返回

四、DefaultSingletonBeanRegistry#getSingleton

此时单例池singletonObjects中并没有beanName为a的对象,且并没有正在创建中,所以返回null

五、AbstractBeanFactory#doGetBean

调用getSingleton方法并传入beanName+Lambda表达式

六、DefaultSingletonBeanRegistry#getSingleton

  1. 此时singletonObjects中没有a
  2. 标记a正在创建中
  3. 执行传入的Lambda表达式,即createBean方法

七、AbstractAutowireCapableBeanFactory#createBean

createBean - doCreateBean

八、AbstractAutowireCapableBeanFactory#doCreateBean

  1. Bean的实例化
  2. 可以看到,Bean对象已经创建(A@2126)
  3. 添加到singletonFactories中(key为beanName,value为ObjectFactory)

九、AbstractAutowireCapableBeanFactory#getEarlyBeanReference

并非将已经实例化但未初始化的Bean对象直接放入singletonFactories(三级缓存)中,考虑到代理对象,所以放入的是Lambda表达式,也就是该方法的执行逻辑

十、DefaultSingletonBeanRegistry#addSingletonFactory

放入singletonFactories(三级缓存)中,key为beanName,value为一个Lambda表达式

执行A的属性填充(执行过程中发现A依赖B,就去执行B的实例化逻辑)

一、AbstractAutowireCapableBeanFactory#doCreateBean

填充Bean

二、AbstractAutowireCapableBeanFactory#populateBean

  1. @Autowired注解是通过AutowiredAnnotationBeanPostProcessor解析的
  2. 这里执行AutowiredAnnotationBeanPostProcessor的postProcessProperties方法

三、AutowiredAnnotationBeanPostProcessor#postProcessProperties

找到A中的b字段需要注入

四、InjectionMetadata#inject

调用AutowiredAnnotationBeanPostProcessor中的inject方法

五、AutowiredAnnotationBeanPostProcessor#inject

调用DefaultListableBeanFactory的resolveDependency方法

六、DefaultListableBeanFactory#resolveDependency

resolveDependency - doResolveDependency

七、DefaultListableBeanFactory#doResolveDependency

  1. autowiredBeanName:依赖的beanName
  2. instanceCandidate:依赖的bean类型

八、DependencyDescriptor#resolveCandidate

调用DefaultListableBeanFactory的getBean方法,此时beanName为b,也就是接下来要执行B的实例化、属性填充、初始化逻辑

执行B的实例化

一、AbstractBeanFactory#getBean

getBean - doGetBean

二、AbstractBeanFactory#doGetBean

此时容器中没有b对象,返回null

三、AbstractAutowireCapableBeanFactory#createBean

createBean - doCreateBean

四、AbstractAutowireCapableBeanFactory#doCreateBean

  1. Bean的实例化
  2. 实例化后的Bean对象和Bean的类型
  3. 将b和对应的Lambda表达式添加到三级缓存中
  4. 此时三级缓存中存在a,b两个元素
  5. 填充b对象属性

 

执行B的属性填充

一、AbstractAutowireCapableBeanFactory#populateBean

同样的,通过AutowiredAnnotationBeanPostProcessor的postProcessProperties方法中处理@Autowired注解

二、AutowiredAnnotationBeanPostProcessor#postProcessProperties

找到B依赖A

三、InjectionMetadata#inject

执行AutowiredAnnotationBeanPostProcessor的inject方法进行属性注入

四、AutowiredAnnotationBeanPostProcessor#inject

调用DefaultListableBeanFactory的resolveDependency方法

五、DefaultListableBeanFactory#resolveDependency

resolveDependency - doResolveDependency

六、DefaultListableBeanFactory#doResolveDependency

获取到注入的beanName和类型,调用DependencyDescriptor的resolveCandidate方法

七、DependencyDescriptor#resolveCandidate

从容器中获取a对象

八、AbstractBeanFactory#getBean

getBean - doGetBean

九、DefaultSingletonBeanRegistry#getSingleton

此时发生了改变

  1. 从singletonObjects(一级缓存)中获取a,没有
  2. beanName为a的Bean正在创建
  3. 从earlySingletonObjects(一级缓存)中获取a,同样没有
  4. 但是,从三级缓存singletonFactories中获取a,能获取到,此时执行三级缓存中a对应的Lambda表达式的逻辑
  5. 执行Lambda表达式后拿到a对象
  6. 将a对象(实例化了但未进行初始化)放入二级缓存中
  7. 删除三级缓存中的a

 

十、AutowiredAnnotationBeanPostProcessor#inject

通过反射将a对象赋值给b对象的a字段

执行B的初始化

一、AbstractAutowireCapableBeanFactory#doCreateBean

调用initializeBean执行b对象后续的初始化逻辑

二、AbstractAutowireCapableBeanFactory#initializeBean

  1. Aware接口方法的回调(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware)
  2. BeanPostProcessor的初始化前方法回调
  3. InitializingBean的afterPropertiesSet方法回调和自定义的初始化方法回调
  4. BeanPostProcessor的初始化后方法回调
  5. 返回完成初始化的b对象

三、DefaultSingletonBeanRegistry#getSingleton

  1. 此时已经执行完b对应的Lambda表达式的doCreateBean的逻辑,拿到的是b已经实例化并初始化好的Bean对象
  2. 删除b正在创建的标识
  3. 将b添加到一级缓存singletonObjects单例池中,删除三级缓存和二级缓存中的b
  4. 返回已经实例化并初始化好的b对象

执行A的属性填充(此时依赖的B已经完成了实例化和初始化放到容器的单例池中,接着执行之前没有执行完成的A的属性填充逻辑)

一、AutowireAnnotationBeanPostProcessor#inject

通过反射将b对象赋值给a对象的b字段(b对象中的a字段此时的值为完成了实例化但未进行初始化的a对象,没有进行初始化的对象并不影响别的对象去引用,后续对a对象进行初始化即可)

执行A的初始化

一、AbstractAutowireCapableBeanFactory#doCreateBean

执行a对象的初始化逻辑

二、DefaultSingletonBeanRegistry#getSingleton

执行完a对象的初始化逻辑,将a添加到一级缓存singletonObjects中,删除三级缓存和二级缓存中的a,至此完成了相互引用的a和b对象的实例化和初始化逻辑,并将它们放入了容器的单例池中

http://www.lryc.cn/news/607541.html

相关文章:

  • 插件升级:Chat/Builder 合并,支持自定义 Agent、MCP、Rules
  • 小学阶段的学习机推荐:科大讯飞T30、Lumie 10学习机暑期16项AI功能升级
  • 代码随想录day52图论3
  • Effective C++ 条款15:在资源管理类中提供对原始资源的访问
  • ICML 2025 | 深度剖析时序 Transformer:为何有效,瓶颈何在?
  • qt中的手势
  • STM32学习记录--Day5
  • 操作系统-lecture4(进程的调度)
  • win10 VC++6.0 应用程序无法正常运行 0xc0000142,应用程序无法正常启动,报错“0xc0000142”,解决办法
  • 深度解读 CSGHub:开源协议、核心功能与产品定位
  • Springboot 配置 doris 连接
  • Spring Boot 异步执行方式全解析:@Async、CompletableFuture 与 TaskExecutor 对比
  • JavaWeb笔记2-JavaScriptVueAjax
  • 备案主体更换期间网站可以访问吗
  • opencv-python的GPU调用
  • 树莓派GPIO介绍 + LED控制
  • 智能Agent场景实战指南 Day 28:Agent成本控制与商业模式
  • xcode swift项目运行、连接真机运行报错,引入文件夹失败
  • [2025CVPR-图象生成方向]ODA-GAN:由弱监督学习辅助的正交解耦比对GAN 虚拟免疫组织化学染色
  • python PIL图片转base64字符串
  • 练习javaweb+mysql+jsp
  • 告别“AI味”图像!最新开源AI模型FLUX.1-Krea实现真实光影生成
  • [CISCN 2022 初赛]online_crt
  • 【PHP 自动加载机制详解】
  • 四、基于SpringBoot,MVC后端开发笔记
  • Qwen2 RotaryEmbedding 位置编码仅仅是第一层有吗
  • 提问总结2
  • Eden 和 Survivor 比例可以调整么,参数是什么?还用到了哪些参数?
  • SpringCloud(一)微服务基础认识
  • U-Net vs. 传统CNN:为什么医学图像分割需要跳过连接?