1、spring提供了三种依赖注入的方式,先来看一下各个注入方式的实现方法以及各自的优缺点
1)基于字段注入的方式
该方式使用@Autowired方法就可以实现类的注入
@Component
public class ClassB {
@Autowired
private ClassA classA;
public void testMethod1() {
classA.method1();
}
}
这种注入方式的优点就是实现简单,通过一个注解就可以完成注入。但是这样的弊端却有很多,是最不推荐的一种注入方式。
- 当ClassA没有被Spring管理时,则通过@Autowrite注解注入的ClassA则是null,此时调用A的方法会出现空指针异常。而且脱离了容器环境就不能够使用独立的使用ClassB中的ClassA对象,比如代码段:
ClassB classB = new ClassB();
classB.classA.method1();
调用该代码就会出现空指针异常,这样就使得跟Spring框架强行绑定了,脱离框架无法使得代码正确运行
- 无法注入一个final类型的属性,这是由于final类型的字段必须在类实例化的时候进行实例化,而Spring的属性注入是在实例化完成之后通过AbstractAutowireCapableBeanFactory#populateBean方法进行属性填充的
- 第三点也是最容易忽略的一点,在存在循环依赖问题时,通过@Autowrite方式进行注入时,项目编译不会报错,但是调用循环依赖的方法时则会报错。所以@Autowrite方式不是解决了循环依赖的问题而是将问题隐藏了,这样更致命。
2)基于构造方法的方式进行注入
@Component
public class ClassB {
private final ClassA classA;
@Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
public void testMethod1() {
classA.method1();
}
}
通过对比上一种方法的缺点,我们看一下通过构造方法注入的优点。
- 通过构造方法注入可以脱离Spring框架使用注入的类,下面那段代码不会报空指针异常
ClassB classB = new ClassB(new ClassA());
classB.testMethod1();
- 可以注入final类型的属性,并且能够保证注入的属性都不为空
- 如果出现循环依赖的情况,通过该构造方法注入的方式注入的时候编译期间就会报异常
- 缺点就是如果注入的类比较多,或者有的类不是强制需要的时候就会增加构造方法的复杂度
3)set方法注入
@Component
public class ClassB {
private ClassA classA;
@Autowired
public void setClassA(ClassA classA) {
this.classA = classA;
}
public void testMethod1() {
classA.method1();
}
}
- 通过set方法进行注入的时候可以对依赖进行按需注入,避免了构造方法注入的时候许多依赖注入时候的问题
- set方法注入可以多次重复注入
- set方法注入不会发生循环依赖问题