IoC 和 DI 是 Spring 中最重要的两个概念,其中 IoC 为控制反转的思想,而 DI 依赖注入是 IoC 的具体实现。
# 概述
在 Spring 中实现依赖注入的常见方式有以下 3 种:
- 属性注入(Field Injection);
- Setter 注入(Setter Injection);
- 构造方法注入(Constructor Injection)。
# 属性注入
属性注入是日常开发中使用最多的一种注入方式:
1 2 3 4 5 6 7 8 9 10 11
| @RestController public class UserController { @Autowired private UserService userService;
@RequestMapping("/add") public UserInfo add(String username, String password) { return userService.add(username, password); } }
|
# 优点
属性注入最大的优点就是实现简单、使用简单,只需要给变量上添加一个注解(@Autowired),就可以在不 new 对象的情况下,直接获得注入的对象了(这就是 DI 的功能和魅力所在),所以它的优点就是使用简单。
# 缺点
属性注入虽然使用简单,但是也存在很多问题,甚至编译器 Idea 都会提醒你 “不建议使用此注入方式”,Idea 的提示信息如下:
属性注入的缺点主要包含以下 3 个:
- 功能性问题:无法注入一个不可变的对象(final 修饰的对象);
- 通用性问题:只能适应于 IoC 容器;
- 设计原则问题:更容易违背单一设计原则。
# Setter 注入
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @RestController public class UserController { 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 修饰的对象);
- 注入的对象可被修改。
# 构造方法注入
构造方法注入是 Spring 官方从 4.x 之后推荐的注入方式,它的实现代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @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); } }
|
当然,如果当前的类中只有一个构造方法,那么 @Autowired 也可以省略,所以以上代码还可以这样写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @RestController public class UserController { private UserService userService;
public UserController(UserService userService) { this.userService = userService; }
@RequestMapping("/add") public UserInfo add(String username, String password) { return userService.add(username, password); } }
|
# 优点
- 可注入不可变对象;
- 注入对象不会被修改;
- 注入对象会被完全初始化;
- 通用性更好。