首页 > 其他分享 >Spring 是如何解决循环依赖的

Spring 是如何解决循环依赖的

时间:2023-10-05 22:34:51浏览次数:36  
标签:缓存 Spring beanName bean 依赖 singletonObject 循环

首先我们要了解spring 实例化bean的三步骤:
1) doCreateBeanInstance,通过无参构造方法创建一个bean的实例。
2) populateBean,填充bean的属性。
3) initialBean, 执行bean的初始化。
Spring的循环依赖主要发生在第一步和第二步。

Spring的依赖注入有三种情况:

1. 构造器注入,对于构造器注入形式的循环依赖, Spring框架无法自己解决。
2. 对于prototype 作用域类型的bean,形成的循环依赖,Spring框架也无法解决,因为Spring框架对prototype作用域的bean是不缓存的,无法提前暴露一个创建中的bean解决。
3. 对于setter形式的注入,形成的循环依赖,Spring框架是通过三级缓存解决的。
1) 一级缓存, singletonObjects。
2) 二级缓存, earlySingletonObjects。
3) 三级缓存,singletonFactories, 类型为ObjectFactory。

    /** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
 
    /** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    /** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

看一下getSingleton源码:

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

通过ObjectFactory将被依赖的bean提前暴露出去,那么在用三级缓存的时候可以直接get出来。

标签:缓存,Spring,beanName,bean,依赖,singletonObject,循环
From: https://www.cnblogs.com/wyl010926/p/17744044.html

相关文章

  • Spring 的几种配置方式
    1、xml配置文件<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http......
  • Spring Boot
    1.什么是SpringBoot?   SpringBoot是Spring开源组织下的子项目,是Spring组件一站式解决方案,主要是简化了使用   Spring的难度,简省了繁重的配置,提供了各种启动器,使开发者能快速上手。2.为什么要用SpringBoot   快速开发,快速整合,配置简化、内嵌服务容器3.......
  • SpringCloud2022
    1.父模块<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.5</version></parent><properties><java.version>1......
  • forEach中return会退出循环吗 (改)
    forEach循环在JavaScript中的forEach循环中使用return语句,并不会退出或终止循环,forEach循环会继续执行完剩余的所有迭代。forEach循环中的return语句只会从当前的迭代回调函数中返回,而不会中断整个循环。举例来说:constarray=[1,2,3,4,5];array.forEach(num=>{if......
  • sa-token在springcloud中充当什么角色
    sa-token是干什么的?SA-Token是一种用于身份验证和授权的令牌。SA-Token全称为ServiceAccountToken,它是由GoogleCloud平台提供的一种身份验证机制。SA-Token用于向服务账号提供身份验证和授权,使其能够访问特定的GoogleCloud资源和API。SA-Token通过使用JSONWebToken(JWT)来生......
  • springboot开发过程的一些细节
    注解:格式要求@DateTimeFormat(pattern=“yyyy-MM-DD”)@Pathvariable用来绑定动态请求参数@RequestBody用来接收前端传来的动态请求参数,一般post请求,对象接收。 在Controller层中返回值参数要与需求文档的参数相同。依赖:pagehelper依赖,实现分页更能跟便捷......
  • SpringBoot vue云办公系统
    SpringBootvue云办公系统系统功能云办公系统登录员工资料管理:搜索员工添加编辑删除员工导入导出excel薪资管理:工资账套管理添加编辑删除工资账套员工账套设置系统管理:基础信息设置部门管理职位管理职称管理权限组管理操作员管理开发环境和技术开发语言:Ja......
  • 全脸 苦思设计了半年的注册中心,与spring cloud 的做法 基本一致
    早知道不去自己思考设计了,害死了不少脑细胞,物理层的东西,所有设计者的思路都基本一致;  ......
  • SpringSecurity-前后端分离教程
    1、简介SpringSecurity是Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。一般来说中大型的项目都是使用SpringSecurity来做安全框架。小项目有Shiro的比较多,因为相比与SpringSecurity,Shiro的上手更加的简单。......
  • Bean 的作用域有哪些?如何在 Spring 中创建 Bean?
    Bean的作用域有哪些?在Spring中,Bean的作用域定义了Bean实例的生命周期和可见性。Spring定义了以下五种作用域:1、singleton:单例模式,一个Bean容器中只存在一个实例。2、prototype:每次请求都会创建一个新的实例。3、request:每个HTTP请求都会创建一个新的实例。4、ses......