Spring是如何解决循环依赖的?

news2025/1/17 13:57:54

一、什么是循环依赖?

循环依赖:说白了就是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了一个环形调用。

  • 第一种情况:自己依赖自己的直接依赖
    在这里插入图片描述

  • 第二种情况:两个对象之间的直接依赖
    在这里插入图片描述

  • 第三种情况:多个对象之间的间接依赖
    在这里插入图片描述

二、循环依赖的N种场景

在这里插入图片描述

2.1 单例的setter注入

这种注入方式应该是spring用的最多的,代码如下:

@Service
publicclass TestService1 {

    @Autowired
    private TestService2 testService2;

    public void test1() {
    }
}
@Service
publicclass TestService2 {

    @Autowired
    private TestService1 testService1;

    public void test2() {
    }
}

这是一个经典的循环依赖,但是它能正常运行,得益于spring的内部机制,让我们根本无法感知它有问题,因为spring默默帮我们解决了。

spring内部有三级缓存

  • singletonObjects:一级缓存,用于保存实例化、注入、初始化完成bean实例;
  • earlySingletonObjects:二级缓存,用于保存实例化完成bean实例;
  • singletonFactories: 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。

2.2 多例的setter注入

这种注入方式偶然会有,特别是在多线程的场景下,具体代码如下:

@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TestService1 {

    @Autowired
    private TestService2 testService2;

    public void test1() {

    }
}
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TestService2 {

    @Autowired
    private TestService1 testService1;

    public void test2() {

    }

}

很多人说这种情况spring容器启动会报错,其实是不对的。

其实在 AbstractApplicationContext 类的 refresh方法中告诉了我们答案,它会调用 finishBeanFactoryInitialization方法,该方法的作用是为了spring容器启动的时候提前初始化一些bean。该方法的内部又调用了 preInstantiateSingletons方法
在这里插入图片描述
标红的地方明显能够看出:非抽象、单例并且非懒加载的类才能被提前初始化bean。而多例即SCOPE_PROTOTYPE
类型的类,非单例,不会被提前初始化bean,所以程序能够正常启动。
在这里插入图片描述
只需要再定义一个单例的类,在它里面注入TestService1

@Service
public class TestService3 {

    @Autowired
    private TestService1 TestService1;
}

在这里插入图片描述

注意:这种循环依赖问题是无法解决的,因为它没有用缓存,每次都会生成一个新对象

2.3 构造器注入

@Service
public class TestService4 {

    public TestService4(TestService5 testService5) {
    }
}
@Service
public class TestService5 {

    public TestService5(TestService4 testService4) {
    }
}

运行结果:
在这里插入图片描述

构造器注入只是添加了三级缓存,并没有使用缓存,所以也无法解决循环依赖问题

2.4 单例的代理对象setter注入

这种注入方式其实也比较常用,比如平时使用:@Async 注解的场景,会通过AOP自动生成代理对象

2.5 DependsOn循环依赖

还有一种有些特殊的场景,比如我们需要在实例化Bean A 之前,先实例化Bean B,这个时候就可以使用@DependsOn注解

@Service
@DependsOn(value = "testService9")
public class TestService8 {

    @Autowired
    private TestService9 testService9;

    public void test8() {

    }
}
@Service
@DependsOn(value = "testService9")
public class TestService8 {

    @Autowired
    private TestService9 testService9;

    public void test8() {

    }
}

三、出现循环依赖如何解决?

循环依赖划分

  • 生成代理对象产生的循环依赖
  • 使用@DependsOn产生的循环依赖
  • 其他循环依赖
    • 多例循环依赖
    • 构造器循环依赖

3.1 生成代理对象产生的循环依赖

这类循环依赖问题解决方法很多,主要有:

  1. 使用@Lazy注解,延迟加载;
  2. 使用@DependsOn注解,指定加载先后关系;
  3. 修改文件名称,改变循环依赖类的加载顺序

3.2 使用@DependsOn产生的循环依赖

3.3 多例循环依赖

这类循环依赖问题可以通过把bean改成单例的解决

3.4 构造器循环依赖

这类循环依赖问题可以通过使用@lazy注解解决

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/155743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 深入系统完全讲解(11)

9 framework 内容组成 狭义的 framework,主要讲的就是 SystemServer 里面的所有服务,这些是在 framework, 而广义的就是包含了 rec,native 服务,系统 app 等一切分不出去的模块,所以 framework 要能做好&a…

睿尔曼 RM65-B 机械臂 WIN 示教软件测试

大家好,我是虎哥,最近开始接触机械臂,尤其是协作机械臂,小,轻、还价格便宜一点,由于我师兄弟强烈推荐的睿尔曼 RM65-B机械臂,所以总结一下自己的开箱测试经验,主要是在WIN下 示教器软…

Protobu编译本地环境搭建

1 windows下安装Protobuhttps://github.com/protocolbuffers/protobuf/releases2 安装cmakehttps://cmake.org/download/3选择选择你的VS版本4生成pb运行程序5 protoc --cpp_out生产pb文件将刚才编译后的libprotobufd.lib和protoc.exe拷贝到自己创建的项目下,按住sh…

express中间件

文章目录中间件定义一个最简单的中间件自定义中间件中间件的五个使用注意事项Express 基于 Connect 构建而成,因此,它也保持了重用中间件来完成基础任务的想法。这就意味着,通过 Express 的 API 方便地构建 Web 应用地同时,又不失…

基于vgg16和pytorch框架进行cifar10数据集的图像分类

vgg16网络模型的实现 这里只讲怎么实现 百度搜到vgg16的网络模型图,用pytorch框架进行实现 图是这样,用pytorch实现就行,pyotrch不太熟悉的话可以去看小土堆的视频 命名mode.py 也可以使用其他名字,在后面的train.py里面改一下也…

【C语言进阶】内存函数和结构体内存对齐

目录一.strerror函数1.错误码变量errno2.strerror函数的使用3.perror函数二.memcpy函数1.函数介绍2.模拟实现三.memmove函数1.函数介绍2.模拟实现四.结构体的内存对齐一.strerror函数 1.错误码变量errno 规定: C语言库函数如果出现运行错误,会将对应错误信息的错误…

联邦学习 (FL) 中常见的3种模型聚合方法的 Tensorflow 示例

联合学习 (FL) 是一种出色的 ML 方法,它使多个设备(例如物联网 (IoT) 设备)或计算机能够在模型训练完成时进行协作,而无需共享它们的数据。 “客户端”是 FL 中使用的计算机和设备,它们可以彼此完全分离并且拥有各自不…

基于Java springmvc+mybatis酒店信息管理系统设计和实现

基于Java springmvcmybatis酒店信息管理系统设计和实现 博主介绍:5年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取…

程序员接私活的几个平台和建议,避免掉坑!

大家对于程序员接私活这件事的看法,褒贬不一。但是你如果确实用钱,价格又合适,那就大胆去接。 如果不那么缺钱,那么接私活之前先考虑清楚,如果自己将空余时间用在接私活所产生的价值是不是大于提升自己。如果是的话&a…

2022年 大学生工程训练比赛[物料搬运]

本人和团结参加了2022年大学生工程训练(简称工训赛)校赛选拔,准备了几个月的时间和花费了较多的资金,由于疫情等多种情况,很遗憾未能参加湖南省省赛,过了这么久还是写个博客记录参赛准备和调试过程。 目录 一、比赛要求 二、整体…

第十章面向对象编程(高级部分)

10.1 类变量和类方法(关键字static) 10.1.31类变量快速入门 思考: 如果,设计一个 int count 表示总人数,我们在创建一个小孩时,就把 count 加 1,并且 count 是所有对象共享的就 ok 了! package com.hspedu.static_;public class ChildGame {…

MS【1】:Metric

文章目录前言1. Dice Loss1.1. Dice coefficient1.2. F1 score - Dice1.3. Dice Loss2. Sensitivity & Specificity2.1. Sensitivity2.2. Specificity3. Hausdorff distance3.1. 概念3.2. 单向 Hausdorff distance3.3. 双向 Hausdorff distance3.4. 部分 Hausdorff distanc…

使用ResNet18实现CIFAR100数据集的训练

如果对你有用的话,希望能够点赞支持一下,这样我就能有更多的动力更新更多的学习笔记了。😄😄 使用ResNet进行CIFAR-10数据集进行测试,这里使用的是将CIFAR-10数据集的分辨率扩大到32X32,因为算力相关的…

二、数据仓库模型设计

数据仓库模型设计一、数据模型二、关系模型三、维度模型1、事实表(1)事务事实表(2)周期快照事实表(3)累计快照事实表(4)无事实的事实表2、维度表3、维度模型类型(1&#…

LVGL学习笔记16 - 进度条Bar

目录 1. Parts 2. 模式 2.1 LV_BAR_MODE_SYMMETRICAL:对称模式 2.2 LV_BAR_MODE_RANGE:范围模式 3. 动画 4. 样式 4.1 方向 4.2 渐变色 4.3 增加边框 4.4 滚动条方向 进度条有一个背景和一个指示器组成,通过lv_bar_create创建对象。…

mysql多表查询

一、关联查询(联合查询) 1.1 什么是关联查询 关联查询:两个或者多个表,一起查询。 前提条件: 这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段&#x…

初识IL2CPP

在Unity中进行打包时,有两种打包方式选择:Mono和IL2CPP Mono和IL2Cpp是Unity的脚本后处理方式,通过脚本后处理实现Unity的跨平台 1.Mono (1). Mono组成组件: C#编辑器,CLI虚拟机,以及核心类别程序库 (2).跨平台过程 Mo…

【Linux】多线程概念

目录🌈前言🌸1、Linux线程概念🍡1.1、概念🍢1.2、线程的优点🍧1.3、线程的缺点🍨1.4、线程的异常和用途🌺2、Linux下进程 vs 线程🌈前言 这篇文章给大家带来线程的学习!…

PID算法入门(一)

1.简介 PID是Proportional(比例), Integral(积分), Differential(微分)的首字母缩写,他是一种结合比例,积分,微分三个环节于一体的闭环控制算法. 2.PID各环节 2.1比例环节 成比例地反应控制系统的偏差信号,即输出&a…

Codeforces Round #843 (Div. 2) A1 —— D

题目地址:Dashboard - Codeforces Round #843 (Div. 2) - Codeforces一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055qq.com Time of completion:2023.1.11 Last edited: 2023.1.11 目录 ​编辑 A1. Gardener…