依赖注入原理
参考文章:https://www.51cto.com/article/716969.html
Spring 中的依赖注入是通过反射来实现的,当 IOC 容器创建 Bean 的时候,会检查 Bean 中定义的依赖关系,并且尝试通过反射来注入这些依赖关系
Spring 的依赖注入有三种方式:
- 属性注入
@RestController
public class UserController {
// 属性对象
@Autowired
private UserService userService;
@RequestMapping("/add")
public UserInfo add(String username, String password) {
return userService.add(username, password);
}
}
优点:
- 使用简单,添加
@Autowired
即可
缺点:
- 无法注入一个不可变对象(final 修饰),因为 Java 中的 final 对象,要么初始直接赋值,要么在构造方法中赋值,如果使用属性注入 final 对象,不符合 Java 的 final 使用规范
@Autowired
private final UserService userService;
- 与 IOC 容器耦合度过高,只能适用于 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(String username, String password) {
return userService.add(username, password);
}
}
优点:
- setter 注入只针对一个对象,符合单一职责原则
缺点:
- 不能注入不可变对象(final 修饰的对象)
- 注入的对象可被修改(在注入之后,如果在其他地方调用 setXX 会改变注入的对象)
- 构造方法注入
Spring 4.x 之后推荐的注入方式
如果只有一个构造方法,可以不用在构造方法上添加@Autowired
,如下边代码,可以去掉@Autowired
注解:
@RestController
public class UserController {
// 构造方法注入
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@RequestMapping("/add")
public UserInfo add(String username, String password) {
return userService.add(username, password);
}
}
优点:
- 可以注入不可变对象
- 注入对象不会被修改
- 通用性更好,无论是 IOC 框架还是非 IOC 框架,构造方法注入的代码都是通用的