spring依赖注入的三种方式和循环依赖
spring依赖注入的三种方式
一: 属性注入
就是使用注解@Autowired/@Resource注入
@Controller public class StudentController { //1.属性注入 @Autowired StudentService studentService; }
优点:使用简单
缺点:
- 功能性问题:无法注入一个不可变的对象(final 修饰的对象);
- 通用性问题:只能适应于 IoC 容器;
二:setter注入
@Controller public class StudentController { //2.set注入 private StudentService studentService; @Autowired public void setStudentService(StudentService studentService) { this.studentService = studentService; } }
缺点:
- 不能注入不可变对象(final 修饰的对象);
- 注入的对象可被修改。因为对外提供了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再完成它的整个生命周期。至此,循环依赖结束
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)