开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
IoC 和 DI 是 Spring 中最重要的两个概念,其中 IoC(Inversion of Control)为控制反转的思想,而 DI(Dependency Injection)依赖注入为其(IoC)具体实现。
简介
在Spring 中实现依赖注入的常见方式有三种:
- 属性注入
- Setter 注入
- 构造方法注入
属性输入
常用方法,用注解 @Autowired 或者 @Resource 实现
代码示例
public class PorpertyBasicsService {
@Autowired
PropertyBasicsDao propertyBasicsDao;
@Resource
PropertyBasicsMapper basicsMapper;
}
优点
实现简单、使用简单,只需要给变量上添加注解,就可以在不 new 对象的情况下直接获得注入的对象。
缺点
- 无法注入一个 final 对象 - 功能性问题
- 只能适用于 IoC 容器 - 通用性问题
- 容易违背单一设计原则 - 设计原则问题
功能性问题
在 Java 中 final 对象(不可变)要么直接赋值,要么在构造方法中赋值,所以当使用属性注入 final 对象时,它不符合 Java 中 final 的使用规范,所以就不能注入成功了。
ps:如果要注入一个不可变对象,使用构造方法注入就行
通用性问题
使用属性注入的方式只适用于 IoC 框架(容器) ,如果将属性注入的代码移植到其他非 IoC 的框架中,那么代码就无效了,所以属性注入的通用性不是很好。
设计原则问题
注入实现越简单,那么滥用它的概率也越大,所以出现违背单一职责原则的概率也越大。
Setter 注入
代码示例
@RestController
public class UserController {
// Setter 注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
@RequestMapping("/add")
public UserInfo add(UserInfo userinfo) {
return userService.add(userinfo);
}
}
优点
完全符合单一职责的设计原则,每一个Setter只针对一个对象。
缺点
- 不能注入 final 对象
- 注入的对象可以被修改
第一点不能注入final对象和上面 一个问题差不多,final 对象会报错
第二点就是任何地方都可以调用他的 set 方法来改变注入对象,意味被注入的对象随时会被修改
构造方法注入
代码示例
@RestController
public class UserController {
// 构造方法 注入
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@RequestMapping("/add")
public UserInfo add(UserInfo userinfo) {
return userService.add(userinfo);
}
}
如果当前的类中只有一个构造方法,那么@Autowired 也可以省略。
使用 lombok 的 @AllArgsConstructor 注解 可以免去构造方法
优点
可以注入 final 对象
@Service
@AllArgsConstructor
public class PropertyBasicsServiceImpl{
private PropertyBasicsMapper propertyBasicsMapper;
}
注入对象不会被修改
构造方法在对象创建时只会执行一次,因此它不存在注入对象被随时(调用)修改的情况。
完全初始化
因为依赖对象是在构造方法中执行的,而构造方法是在对象创建之初执行的,因此被注入的对象在使用之前,会被完全初始化,这也是构造方法注入的优点之一。
通用性更好
构造方法和属性注入不同,构造方法注入可适用于任何环境,无论是 IoC 框架还是非 IoC 框架,构造方法注入的代码都是通用的,所以它的通用性更好。