Spring注解之依赖注入@Autowired和@Resource

Spring常见的DI方式

字段注入(Field Injection)

  • 在字段上使用@Autowired/Resource注解

  • 字段注入是日常开发中使用最多的一种注入方式,它的实现代码如下:

    @Autowired
    private UserService userService;
    
    优点

    属性注入最大的优点就是实现简单、使用简单,只需要给变量上添加一个注解 @Autowired,就可以在不 new 对象的情况下,直接获得注入的对象了(这就是 DI 的功能和魅力所在),所以它的优点就是使用简单。

    缺点

    属性注入虽然使用简单,但也存在着很多问题,甚至编译器 Idea 都会提醒 “不建议使用此注入方式”

    1、功能性问题:无法注入一个不可变的对象(final 修饰的对象)
    2、通用性问题:只能适应于 IoC 容器
    3、设计原则问题:更容易违背单一设计原则

Setter注入(Setter Injection)

  • 调用Setter的方法注入依赖

  • 实现代码如下:

    // Setter 注入
    private UserService userService;
    
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    

    从上面代码可以看出,Setter 注入比属性注入要麻烦很多。
    要说 Setter 注入有什么优点的话,那么首当其冲的就是它完全符合单一职责的设计原则,因为每一个 Setter 只针对一个对象。
    但它的缺点也很明显,它的缺点主要体现在以下 2 点:

    1、不能注入不可变对象(final 修饰的对象);
    2、注入的对象可被修改。

    • Setter 注入提供了 setXXX 的方法,意味着你可以在任何时候、在任何地方,通过调用 setXXX 的方法来改变注入对象,所以 Setter 注入的问题是,被注入的对象可能随时被修改。

构造器注入(Constructor Injection)

  • 利用构造方法的参数注入依赖

  • 构造方法注入是 Spring 官方从 4.x 之后推荐的注入方式,它的实现代码如下:

    // 构造方法注入
    private UserService userService;
    @Autowired
    public UserController(UserService userService) {
    	this.userService = userService;
    }
    

    如果当前的类中只有一个构造方法,那么 @Autowired 也可以省略

    优点

    构造方法注入相比于前两种注入方法,它可以注入不可变对象,并且它只会执行一次,也不存在像 Setter 注入那样,被注入的对象随时被修改的情况,它的优点有以下 4 个:

    1、可注入不可变对象(final 修饰的对象)
    2、注入对象不会被修改

    • 构造方法注入不会像 Setter 注入那样,构造方法在对象创建时只会执行一次,因此它不存在注入对象被随时(调用)修改的情况。

    3、注入对象会被完全初始化

    • 因为依赖对象是在构造方法中执行的,而构造方法是在对象创建之初执行的,因此被注入的对象在使用之前,会被完全初始化,这也是构造方法注入的优点之一。

    4、通用性更好

    • 构造方法和属性注入不同,构造方法注入可适用于任何环境,无论是 IoC 框架还是非 IoC 框架,构造方法注入的代码都是通用的,所以它的通用性更好。

常用注入方式总结

依赖注入的常见实现方式有 3 种:属性注入、Setter 注入和构造方法注入。

  • 其中属性注入的写法最简单,所以日常项目中使用的频率最高,但它的通用性不好;
  • 而 Spring 官方推荐的是构造方法注入,它可以注入不可变对象,其通用性也更好;
  • 如果是注入可变对象,那么可以考虑使用 Setter 注入。

三种注入方式的优缺点

  • 构造器注入:强依赖性(即必须使用此依赖),不变性(各依赖不会经常变动)
  • Setter注入:可选(没有此依赖也可以工作),可变(依赖会经常变动)
  • Field注入:大多数情况下尽量少使用字段注入,一定要使用的话, @Resource相对@Autowired对IoC容器的耦合更低

@Autowired 和 @Resource 有什么区别

@Autowired 和 @Resource 都是 Spring/Spring Boot 项目中,用来进行依赖注入的注解。它们都提供了将依赖对象注入到当前对象的功能,但二者却有众多不同。

  • 来源不同:来自不同的“父类”,@Autowired是Spring提供的,@Resource是JSR-250提供的

  • 依赖查找顺序不同
    依赖注入的功能,是通过先在 Spring IoC 容器中查找对象,再将对象注入引入到当前类中。
    @Autowired 查找顺序: 是先根据类型(byType)查找,如果存在多个(Bean)再根据名称(byName)进行查找
    @Resource 查找顺序: 是先根据名称(byName)查找,如果(根据名称)查找不到,再根据类型(byType)进行查找

  • 支持的参数不同:@Autowired 只支持设置一个 required 的参数,而 @Resource 支持 7 个参数

  • 适用对象不同:@Autowired可以对构造器、方法、参数、字段使用,@Resource只能对方法、字段使用

  • 依赖注入的支持不同:@Autowired 支持属性注入、构造方法注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入

为什么IDEA只对@Autowired警告

在使用IDEA开发的时候有没有注意到过一个提示,在字段上使用Spring的依赖注入注解@Autowired后会出现如下警告:

Field injection is not recommended (字段注入是不被推荐的)

但是使用@Resource却不会出现此提示

  • @Autowired是Spring提供的,它是特定IoC提供的特定注解,这就导致了应用与框架的强绑定,一旦换用了其他的IoC框架,是不能够支持注入的。

  • 而 @Resource是JSR-250提供的,它是Java标准,我们使用的IoC容器应当去兼容它,这样即使更换容器,也可以正常工作。

用@RequiredArgsConstructor代替@Autowired

我们都知道注入一个bean有三种方式(set注入, 构造器注入, 注解注入),spring推荐我们使用构造器的方式注入Bean。

@RequiredArgsConstructor注解,生成带有必需参数的构造函数。必需的参数是最终字段和具有约束的字段,例如@NonNull。

这个注解是基于lombok的使用时必须导入lombok包。

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

同时注意几点:

  1. 声明的变量必须为final

  2. 根据构造器注入的,相当于当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。基于构造方法为属性赋值,容器通过调用类的构造方法将其进行依赖注入。

当我们需要注入Bean的时候可以直接在类上添加@RequiredArgsConstructor注解使用,代替了Autowrited注解。

@RequiredArgsConstructor
@RestController
@RequestMapping("/test")
public class TestController {
    private final TestService testService;
    private final UserService userService;
}
posted @ 2022-09-21 10:25  盗梦笔记  阅读(258)  评论(0编辑  收藏  举报