spring依赖注入的三种方式和循环依赖

spring依赖注入的三种方式

一: 属性注入

就是使用注解@Autowired/@Resource注入

@Controller
public class StudentController {
    //1.属性注入
    @Autowired
    StudentService studentService;
}

优点:使用简单

缺点:

  1. 功能性问题:无法注入一个不可变的对象(final 修饰的对象);
  2. 通用性问题:只能适应于 IoC 容器;

二:setter注入

复制代码
@Controller
public class StudentController {
    //2.set注入
    private StudentService studentService;
    @Autowired
    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }
}
复制代码

缺点:

  1. 不能注入不可变对象(final 修饰的对象);
  2. 注入的对象可被修改。因为对外提供了public的set方法

三:构造方法注入

是spring4.x后推荐的注入方式

复制代码
@Controller
public class StudentController {
    //3.构造方法注入
    private final StudentService studentService;
    @Autowired
    public StudentController(StudentService studentService) {
        this.studentService = studentService;
    }
}
如果当前的类中只有一个构造方法,那么 @Autowired 也可以省略,所以以上代码还可以这样写:

@Controller
public class StudentController {
//3.构造方法注入
private final StudentService studentService;


public StudentController(StudentService studentService) {
this.studentService = studentService;
}
}

复制代码

优点:

  1 可以注入final类型对象

  2 通用性更好,构造方法注入可以适用任何环境,不需要ioc环境

循环依赖

循环依赖产生原因是多个类相互依赖

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true. 

这就是产生循环依赖后启动报错的提示

产生循环依赖说明类的功能设计有问题,正确的做法应该打破循环依赖,偏方是可以在产生循环依赖的类上加@lazy注解或者配置文件里加 

allow-circular-references: true(允许循环依赖)(spring2.6之前默认是true,2.6版本之后改为false)来启动项目,allow-circular-references设为true不一定有用,也可能设为true后提示Despite circular references being allowed, the dependency cycle between beans could not be broken. Update your application to remove the dependency cycle.

spring是靠三级缓存来解决循环依赖的

其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。

当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。

当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取,第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。

紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束

 

posted @   杨吃羊  阅读(425)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示