Spring注入方式
Spring依赖注入的方式有:构造器注入,setter方法注入、属性注入、工厂方法注入,官方3.x版本推荐使用setter方法注入,到4.x之后官方推荐使用构造器注入。
1、构造器注入
通过构造器注入Shop这个Bean到Person中,可以将需要注入的字段声明为final,使其在类实例化期间被初始化。
@Component
public class Person {
private final Shop shop;
@Autowired
public Person(Shop shop) {
this.shop = shop;
}
}
Spring 4.3版本之后,如果类中只有一个构造方法,则Spring会实现一个隐式的自动注入。
@Component
public class Person {
private final Shop shop;
// @Autowired
public Person(Shop shop) {
this.shop = shop;
}
}
2、setter方法注入
@Component
public class Person {
private Shop shop;
@Autowired
public void setShop(Shop shop) {
this.shop = shop;
}
}
3、属性注入
@Component
public class Person {
@Autowired
private Shop shop;
}
4、工厂方法注入
工厂方法实现注入,因为Spring ioc容器以框架的方式提供工厂方法的功能,并以透明的方式提供给开发者,因此手工编写基于工厂方法的注入这种方式不常用。
public class ShopFactory {
public static Shop getShop(){
Shop shop = new Shop();
return shop;
}
}
<bean id="shop" class="xxx.ShopFactory" factory-method="getShop" />
5、注入方式优缺点对比
1.属性注入
优点
- 简单,便于添加新的依赖,项目中使用最多(然而是Spring官方不推荐的方式)
- 减少大量冗余代码
- 新增依赖时不需要修改过多代码
缺点 or 为什么Spring官方不推荐使用这种方式?
- 单一职责侵入,添加依赖过于简单,添加了五个甚至十个依赖都很容易,使我们不易察觉违反单一职责原则的程序。
- 无法声明不可变的字段,字段不能使用final修饰
- 隐藏了依赖关系,使用依赖注入容器将获取依赖对象的职责从类中抽离出来交与IOC容器装配,当类不再为依赖对象负责时应该更明确的使用公有的接口方法或构造器来清楚的表明类需要什么依赖项。使用属性注入则将这些依赖对外进行了隐藏。
- 与依赖注入容器紧耦合,依赖注入的核心思想是受容器管理的类不应该再与容器紧耦合,这个类应该是一个简单的类并且能够被单独实例化,这样在进行单元测试中实例化这个类时不必去启动IOC容器。
2.构造器注入
优点
- 依赖不可变:可以使用final关键字来修饰依赖字段
- 依赖不为空:允许构造函数可以保证一些重要属性在Bean实例化时就设置好
- 单一职责原则:当使用构造函数注入时,如果参数过多可能会促使你主动对类进行拆分
- 完全初始化的状态:保证返回客户端的代码是完全初始化的状态
- 更好的封装类变量:不需要为每个属性指定Setter方法,避免外部错误的调用
- 更利于单元测试:其它两种方式注入,进行单元测试时需要初始化整个Spring的环境
- 避免循环依赖:若存在循环依赖则启动会抛异常
缺点
- 当注入对象特殊多的时候,构造器会显得十分繁琐,可读性和可维护性较差;但此时也应该考虑类的功能是否过多,是否应该拆分
- 灵活性不强,在有些属性是可选的情况下,如果通过构造器注入,需要为可选参数提供一个null值
- 构造器不利于类的扩展和继承,子类需要引用父类复杂的构造函数
3.Setter方法注入
优点
- 注入属性过多时,使用Setter方法更轻便
- 方便在类实例化之后重新对该属性进行配置或注入
缺点
- Setter方法过多会导致代码冗余,维护麻烦
- 会把循环依赖隐藏掉
- 依赖不是不可变的