Bean有几种注入方式?它们有什么区别?
Bean对象中有以下几种注入方式:
- 属性注入
- Setter注入
- 构造方法注入
属性注入
属性注入是我们最熟悉的,也是日常开发最常使用的一种注入方式,它的实现代码如下:
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/add")
public UserInfo add(@RequestParam String username, @RequestParam String password) {
return userService.add(username, password);
}
}
优点:属性注入最大的优点就是实现简单、使用简单。只需要给变量添加一个@AutoWried注释,就可以在不new对象的情况下,直接获得注入对象
缺点:属性注入的缺点主要是有以下两种:
功能性问题:无法注入一个不可变的对象(final修饰)
在Java中final修饰的对象要么直接赋值,要么在构造方法中赋值,所以当使用属性注入final对象时,不符合Java中的final使用规范,所以注入不成功
通用性问题:只能适应与IoC容器,Idea也会提醒不建议使用:
Setter注入
Setter注入的实现代码如下:
@RestController
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
@RequestMapping("/add")
public UserInfo add(@RequestParam String username, @RequestParam String password) {
return userService.add(username, password);
}
}
优点:它符合单一职责的设计原则(一个类应该只负责一项职责或一个功能),因为每一个Setter只针对一个对象
缺点:不能注入不可变的对象(final修饰);注入的对象可以调用多次,也就是注入对象会被修改
构造方法注入
构造方法注入是Spring官方从4.x之后推荐的注入方式,它的实现代码如下:
@RestController
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@RequestMapping("/add")
public UserInfo add(@RequestParam String username, @RequestParam String password) {
return userService.add(username, password);
}
}
如果当前的类只有一个构造方法,那么@Autowired有也可以省略,如:
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@RequestMapping("/add")
public UserInfo add(@RequestParam String username, @RequestParam String password) {
return userService.add(username, password);
}
}
优点:
注入不可变对象:使用构造方法可以注入不可变对象,如下代码:
注入对象不会被修改:构造方法不会像Setter注入那样,构造方法在对象创建只会执行依次,因此它不存在注入对象被随时(调用)修改的情况
完全初始化:因为依赖对象是在构造方法中执行的,而构造方法是在对象创建之初执行的,因此被注入的对象在使用之前,会被完全初始化
通用性更好:构造注入和属性注入不同,构造方法注入可适用于任何环境,无论是IoC框架还是非IoC框架,构造方法注入的代码都是通用的
缺点:不如属性注入简单