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环境
循环依赖
一级缓存(singletonObjects):存放完全初始化好的Bean,可直接使用。
二级缓存(earlySingletonObjects):存放提前暴露的Bean(已实例化但未完成属性填充和初始化)。
三级缓存(singletonFactories):存放Bean工厂对象(ObjectFactory),用于生成未完成初始化的Bean。
过程:
创建Bean A: 实例化A:调用构造函数创建A对象(此时属性未填充)。将A的ObjectFactory存入三级缓存。发现A依赖B:尝试从一级缓存获取B,若不存在则开始创建B。
创建Bean B: 调用构造函数创建B对象。将B的ObjectFactory存入三级缓存。发现B依赖A:尝试从一级缓存获取A,未找到。从三级缓存获取A的ObjectFactory并生成A的早期引用(未完成初始化的A对象,也就是二级缓存内的bean)。将A的早期引用注入B:B完成属性填充和初始化,并移入一级缓存。
完成Bean A的初始化,从一级缓存获取B,A完成属性填充和初始化,移入一级缓存。
注意事项:
-
Spring 只能解决 单例模式(singleton scope)下的、通过 setter / 字段注入的循环依赖。
-
如果使用的是:
-
构造器注入(Constructor injection) → Spring 无法解决,抛出异常;
-
原型模式(prototype scope) → Spring 不做缓存,也无法处理循环依赖。
-
浙公网安备 33010602011771号