小王学习录
- 前言
- 属性注入
- 1. 属性注入的优点
- 2. 属性注入的缺点
- Setter注入
- Setter注入的优点
- Setter注入的缺点
- 构造方法注入
- 1. 构造方法的优点
- 总结
- 补充
- @Aurowired注解和@Resource注解的区别
前言
在前面的文章中介绍了基于注解的方式将Bean存储到Spring中, 接下来介绍如何基于注解的方式从Spring中取对象, 也就是实现DI依赖注入. 本篇文章将会介绍三种依赖注入的方式, 分别是属性注入
, Setter注入
和构造方法注入
. 并介绍其各自优缺点.
属性注入
属性注入要用到注解@Autowired
@Controller
public class UseController {
@Autowired
private UseService useService;
public void print(){
System.out.println("do_useController");
useService.print();
}
}
使用@Autowired自动注入, 就是去Spring容器中找到UseService类的Bean对象. 如果Bean对象只有一个, 则直接将对象注入给useService引用. 如果Bean对象有多个, 则根据引用的名字来进行匹配.
1. 属性注入的优点
属性注入最大的优点就是使用简单, 只需要添加一个@Autowited注解即可.
2. 属性注入的缺点
- 属性注入不能注入给一个final修饰的引用.
原因是final修饰的变量必须要在定义时初始化, 或者在构造方法中对其进行初始化. - 属性注入的通用性差, 只能用于IoC容器中.
- 属性注入违背单一设计原则的可能性大
所谓单一设计原则, 就是一个类只用来完成一个功能.
属性注入的方式使用起来非常简单, 因此程序员很可能在一个类中注入多个对象. 从而使得这个类的单一设计原则被破坏. 因此说属性输入会使程序违背单一设计原则的概率加大.
Setter注入
@Controller
public class UseController {
private UseService useService;
@Autowired
public void setUseService(UseService useService){
this.useService = useService;
}
public void print(){
System.out.println("do_useController");
useService.print();
}
}
使用setter注入, 通过@Autowired从Spring中取出UseService Bean, 作为实参传给setUseService, 然后在setUseService中将其赋值给引用.
Setter注入的优点
在Setter注入中, 每个Setter只针对一个Bean, 所以他符合单一设计原则.
Setter注入的缺点
- 不能注入给一个final修饰的引用
final修饰的变量必须要在定义时初始化, 或者在构造方法中对其进行初始化.
- 注入的对象可被修改.
在程序执行时, 通过调用setUseService方法, 可以对注入的对象进行修改.
构造方法注入
@Controller
public class UseController {
private UseService useService;
@Autowired
public UseController(UseService useService) {
this.useService = useService;
}
public void print(){
System.out.println("do_useController");
useService.print();
}
}
如果类中只有一个构造方法时, @Autowired可以省略. 这是因为Spring官方推荐构造方法的使用, 所以在底层会自动实现@Autowired
1. 构造方法的优点
-
可以注入给final修饰的引用
-
符合单一设计原则
在一次注入中, 只针对一个Bean. -
注入对象不会被改变
由于构造方法只会执行一次, 所以注入的对象不会被改变 -
注入对象会被完全初始化
因为依赖对象的传递是在构造方法中执行的, 而构造方法是在对象创建之初执行的, 所以构造方法注入确保在对象被创建的时候,所有必要的依赖关系都被传递进来并初始化。
举例来说,如果有一个类 A, 它的构造方法接受一个类 B 的对象作为参数, 那么在创建 A 的对象时, 类 B的对象就是被传递的依赖关系, 并且在 A 的构造方法中对 B 的对象进行了初始化. 这确保了在使用 A 的对象时, A 依赖的对象 B是已经准备好并初始化的。
- 通用性更好
构造方法注入可适用非 IoC 框架. 对于IoC框架和非IoC框架. 构造方法注入的代码都是通用的, 所以它的通用性更好.
总结
综上, 依赖注入的实现方式有以上三种. 分别是属性注入, Setter注入和构造方法注入.
属性注入的写法最简单, 使用频率最高. 但缺点也很明确.
Setter注入适用于注入可变对象的场景.
构造方法注入是Spring官方最推荐的注入方法. 明显优势是可以注入对象给final修饰的引用. 通用性更好.
补充
在进行类注入时, 除了使用@Autowired注解之外, 还可以使用@Resource进行注入.
@Aurowired注解和@Resource注解的区别
- 来源不同
@Autowired注解是Spring框架提供的. 而Resource是JDK提供的, 可以在非Spring的环境下使用 - 参数不同
相比于@Autowired来说, @Resource支持更多的参数配置
如Resource可以通过name参数来指定具体的Bean名称.
但是@Autowired可以使用另一个注解@Qualifier注解来指定具体的Bean名称
比如现在有Dog和Cat两个类都实现了Animal接口. 当要依赖注入一个Animal Bean时, 可以通过@Qualifier注解来显式指定要注入的是哪个Bean(注意: @Qualifier不适合于构造方法注入)
@Component
public class Zoo {
@Autowired
@Qualifier("dog")
private Animal animal;
}
- 查找Bean方式不同
@Autowired查找Bean会先根据类型(类名)进行查找, 如果一个类型中有多个Bean, 则会根据对象名来进行匹配.
@Resource查找Bean则是先根据对象名来进行查找, 然后再根据类型来进行查找
也可以参考上面参数不同里面的方式进行查找设置. - 使用范围不同
@Autowired可以用于以上三种注入方式
但@Resource不适用于构造方法注入. - 可选性不同
@Autowired 可以设置非非必需, 即如果找不到匹配的Bean, 属性可以为null. 但可以使用@Autowire(required = true)来设置为必需的(默认为必须).
@Resource 默认是必需的, 不支持可选性. 如果找不到匹配的Bean, 会抛出异常.
总而言之, @Autowired 更为灵活, 而 @Resource 更加标准化, 可以跨平台使用.