Springboot依赖注入Bean的方式
一、@Autowired 与@Resource的区别
@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上
@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
如下:
@Autowired @Qualifier("executor")
private Executor threadPoolTaskExecutor;
@Resource(name="taskExecutor")
private Executor poolTaskExecutor;
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配
二、Field 注入/属性注入
@Autowired注解的一大使用场景就是字段注入。
@Controller
public class UserController {
@Autowired
private UserService userService;
}
通过Java的反射机制
实现,所以private的成员也可以被注入具体的对象
优点
- 代码少,简洁明了。
- 新增依赖十分方便,不需要修改原有代码
缺点
- 容易出现空指针异常。Field 注入允许构建对象实例时依赖的对象为空,导致空指针异常不能在启动时就爆出来,只能在用到它时才发现。
空指针异常不是必现的,与bean的实例化顺序有关。有时,把依赖的bean改个名字就会报空指针异常。 - 会出现循环依赖的隐患。
三、set方法注入
Setter Injection需要依赖@Autowired注解,使用方式与Field Injection有所不同,Field Injection时@Autowired是用在成员变量上,而Setter Injection的时候,@Autowired是用在成员变量的Setter函数上。
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
}
通过调用成员变量的set方法来注入想要使用的依赖对象。
优点
- 注入参数多的时候比较方便。构造器注入参数太多了,显得很笨重
- 能让类在之后重新配置或者重新注入。
缺点
- 有一定风险。set注入是后初始化其依赖对象,如果一个对象在没有完全初始化就被外界使用是不安全的(尤其是在多线程场景下更加突出)。
四、构造器注入
Constructor Injection是构造器注入,是Springboot最为推荐的一种使用方式。
@Controller
public class UserController {
private final UserService userService;
public UserController(UserService userService){
this.userService = userService;
}
}
注意:
不能提供无参构造方法,否则Springboot默认会加载无参的构造方法,Bean实例对象会为null
- Springboot官方建议使用final来修饰成员变量,然后通过构造方法来进行注入。原因:final修饰的成员变量是不能够被修改的;不加final虽然也能注入Bean,但是若被其他人修改为null,可能会导致不必要的问题,所以最好是加final。
通过对象构建的时候建立关系,这种方式对对象创建的顺序会有要求,当然Spring会为你搞定这样的先后顺序,除非你出现循环依赖
,然后就会抛出异常。
Spring 4.x 的时候,Spring 官方在对比构造器注入和 Setter 注入时,推荐使用构造器注入方式:
优点
- 保证注入的组件不可变
- 确保需要的依赖不为空
- 解决循环依赖的问题(若有循环依赖会在项目启动时抛错)
能够保证注入的组件不可变,并且确保需要的依赖不为空。此外,构造器注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。
若手工写构造方法觉得麻烦,也可以使用lombok中的@RequiredArgsConstructor
@RequiredArgsConstructor
public class VerifyController {
private final UserService userService;
private final StudentService studentService;
}
@RequiredArgsConstructor
@RequiredArgsConstructor 注解是针对标有 @NonNull 注解的变量和 final 变量进行参数的构造方法。