@AutoWired与@Resource

参考 :

@Qualifier - 搜索结果 - 知乎

@Autowired和@Resource的区别是什么? - 知乎

面试突击78:@Autowired 和 @Resource 有什么区别? - 掘金

目录

同一类型多个@Bean报错问题

@Resource注解

@Resource的查找顺序

@Resource注解实现依赖注入

@Resource的来源

@Resource的方法参数

@Resource注解的应用范围

@AutoWired

@AutoWired查找顺序

@AutoWired依赖注入方式

@AutoWired来源

@AutoWired方法参数

@AutoWired注解作用范围

@AutoWired与@Resource的区别

@Qualifier

@primary

解决同一类型Bean报错的问题

使用Resource注解解决

使用@AutoWired注解 + @Qualifier注解解决

使用@primary注解解决


我们通过一个小栗子/一个问题,引出@AutoWired注解和@Resource注解还有@Qualifier注解,利用注解解决这个问题,然后在讲解@AutoWired注解和@Resource注解以及有啥区别...

同一类型多个@Bean报错问题

引出一个问题如果同一个类型有多个@Bean

换句话说就是在依赖注入的时候,我们注入一个Bean的时候,Spring中有多个Bean的类型与这个Bean的类型是一样的,但名称不同(Bean名称是唯一的) 这样会有什么问题呢?

这样说可能还是有一点抽象,我们就来举一个例子把.

比如我现在要注入一个名字为user的对象/Bean

@Autowired
private User user;

但是Spring中存在多个User类型的Bean. 比如下面:

@Configuration
public class UserBeans {
    @Bean(name = "user_1")
    public User user1(){
        User user = new User();
        user.setId(21);
        user.setAge(19);
        user.setName("UserBeans-->张三");
        return user;
    }
    @Bean(name = "user_2")
    public User user2(){
        User user = new User();
        user.setId(21);
        user.setAge(19);
        user.setName("UserBeans-->张三");
        return user;
    }
}
//------------StudentUserBeans与上面不是一个类---------
@Configuration
public class StudentUserBeans {
    @Bean(name = "stu_user1")
    public User user1(){
        User user = new User();
        user.setId(21);
        user.setAge(19);
        user.setName("StudentUserBeans-->张三");
        return user;
    }
}

现在有三个类型为User的Bean,但是三个Bean的名称并不一样,因为Spring中规定Bean的名称(也就是id)是唯一的.

当我们运行的时候会发生什么呢???

@AutoWired与@Resource_第1张图片

什么办法可以解决呢 ?

最简单最直接的办法就是,你在存储一个名称为user的Bean,或者将一个Bean的名称修改为Bean.

如果我非要使用那三个其中一个Bean呢?该怎么办?

有两种方法 :

  • 第一种方法 : 使用Resource注解使用自带的name参数来指定使用的Bean名称
  • 第二种方法 : 使用AutoWired注解注入,并且使用Qualifier来进行筛选
  • 第三种方法 : 使用primary注解

我先分别讲解这几个注解,然后在来解决这个问题

@Resource注解

@Resource的查找顺序

既指定name又指定type

@AutoWired与@Resource_第2张图片

如果既指定name又指定type,他就会在Spring查找name和type唯一匹配的bean,如果没有找到就会抛出异常.

只指定name

@AutoWired与@Resource_第3张图片

如果只指定了name的情况,他就会在Spring中查找name唯一匹配的bean,如果找到了则自动装配,没有找到则抛出异常,

只指定type

@AutoWired与@Resource_第4张图片

如果只指定了type,那么在Spring中查找type唯一匹配的bean,如果没有找到就抛出异常.

既没有指定name,也没有指定type

@AutoWired与@Resource_第5张图片

好我们在来整体总结一下 :

依赖注入的功能,是通过先在 Spring IoC 容器中查找对象(分为类型和名称两种查找方式),再将对象注入引入到当前类中

@Resource的查找顺序分为如下四种方式 :

  • 当指定name的时候,按照name唯一匹配的bean进行查找,如果查找到了则进行自动装配,否则抛出异常
  • 当执行type的时候,按照type唯一匹配的bean进行查找,如果查找到了则进行自动装配,否则抛出异常
  • 当既指定name又指定type的时候,按照name和type进行唯一匹配bean进行查找,如果查找到了则进行自动装配,否则抛出异常
  • 当既没有指定name,也没有指定type的时候,先按照name进行查找,如果查找到了就进行自动装配,如果没有查找到,继续按照类型去查找,如果查找到了则进行自动装配,如果没有查找到或者查找出多个bean,那么就抛出异常---->@Resource默认装配顺序

接着我们趁热打铁继续讲解@Resource注解

@Resource注解也可以实现依赖注入(@Resource注解是JDK提供的),但是也与AutoWired有一些区别.

@Resource注解实现依赖注入

@Resource注解实现属性注入

@AutoWired与@Resource_第6张图片

@Resource注解实现setter注入

@AutoWired与@Resource_第7张图片

@Resource注解并不能实现构造方法注入

@AutoWired与@Resource_第8张图片

@Resource注解不能实现构造方法注入,原因是Resource的执行时机比构造方法执行时机晚一些.

@Resource的来源

@Resource是JDK提供的一个注解,遵循JSR-250规范(Java 250 规范提案.

所以@Resource注解适用于所有的Java框架

@Resource的方法参数

@AutoWired与@Resource_第9张图片

@Resource注解提供多个参数,最重要的就是name和type.

@Resource注解的应用范围

@AutoWired与@Resource_第10张图片

@AutoWired

@AutoWired注解也是可以将依赖的对象注入到当前对象中.

我们接下来详细分析一下@AutoWired重要的几点

@AutoWired查找顺序

@AutoWired与@Resource_第11张图片

@AutoWired默认是先按照类型进行匹配Bean,如果匹配了多个Bean就按照name进行匹配,如果还是匹配了多个Bean就会抛出异常.

我们仔细分析@AutoWired的装配顺序

  • 首先先会按照类型进行匹配,如果匹配到了一个唯一Bean就进行自动装配,如果没有匹配到则抛出异常
  • 如果根据类型匹配出多个Bean,就看是否配置了@Qualifier注解
  • 如果没有配置,则默认会按照名称进行匹配,如果查找到了,则会进行自动装配,如果没有查找到就会抛出异常
  • 如果配置了@Qualifier注解则会根据它的参数的名称进行匹配,如果匹配到了则进行自动装配,否则就会抛出异常

@AutoWired依赖注入方式

使用@AutoWired可以实现三种注入,属性注入,setter注入,构造方法注入.

属性注入

@Autowired //使用一个AutoWired这样的一个注解---->自动装配的意思
private UserService userService;//UserService成员属性

属性注入的优点和缺点

优点 :

  • 属性注入只需要在属性上加一个@AutoWired注解,写法简便,可读性高,易维护.

缺点 :

  • 1.不能注入final修饰的属性.

@AutoWired与@Resource_第12张图片

为啥呢 ?

  • 因为我们知道JDK是我们最底层的框架,spring是上层,使用spring也要依赖java的,所以要遵循Java的规范,Java固定被final修饰的属性1.在定义的时候就进行赋值 2.在构造方法内部进行赋值.

所以,是因为不满足Java的规范

  • 2.属性注入只能在IOC容器才能使用(类与IOC容器高度耦合),使用其他容器/框架的时候不能使用属性注入(通用性不好)

  • 3.更容易违背单一职责原则

啥是单一职责原则呢 ?

单一职责原则的核心思想 : 一个类最好只做一件事,只有一个引起它变化的原因

换句话说,类只有单一功能,不要为类实现过多的功能点,以保证实体只有一个引起职责变化的原因

一个类只做一件事,要么做A事情,要么做B事情.只做一件事情

为什么说属性注入更容易违背单一职责原则呢 ?

  • 由于属性注入使用起来简便,这样就更容易使得开发者在类中注入多个对象,就可能会导致滥用的概率大大提高,所以违背单一职责原则的概率就大大提高-->更容易违背 不是一定违背,

setter注入

@AutoWired与@Resource_第13张图片

Setter注入的优缺点

优点 :

  • setter注入满足单一设计/职责原则.

因为setter方法的特性,一个setter方法只对应一个对象,不会有注入多个对象的可能性,所以满足单一设计/职责原则

缺点 :

  • 不能注入final修饰的对象

还是与属性注入的解释是一样的,原因就是JDK是我们最底层的框架,Spring作为上层,要基于JDK/Java的,所以要满足Java的规范,java规定,被final修饰的属性1.在定义的时候进行赋值2.在构造方法内部进行赋值

  • 注入的对象可能会被修改

由于setter方法是可以被多次调用的,有修改的风险,所以注入的对象就可能被修改.

构造方法注入

@AutoWired与@Resource_第14张图片

构造方法注入的优缺点

优点 :

构造方法最牛,上面的缺点,都是俺构造方法的优点.

就比如,属性注入和setter注入都不能解决注入final修饰的属性问题,那对于构造方法注入就能够解决

  • 能够注入final修饰的属性

为什么构造方法可以注入final修饰的属性呢?

原因还是一样的,因为满足Java的规范,被final修饰的属性 一个是定义的时候就进行赋值,一个是在构造方法内部进行赋值.满足第二条,所以可以注入final修饰的属性.

  • 注入的对象不会被修改.

构造方法注入 注入的对象不会被修改,因为构造方法只会执行一次.

  • 构造方法注入是完全初始化的.

因为依赖注入是在构造方法内部执行的,而构造方法又是在类起初创建的时候就执行的,所以会被完全初始化

  • 它的通用性会更好

构造方法注入因为基于java的,JDK是最底层框架,所以无论在哪一个容器/框架都可以适用

缺点 :

  • 构造方法可以注入多个对象,也就违背了单一设计原则
  • 写法不简便

官方建议

在Spring4.2之前推荐的注入用法就是setter注入,因为setter注入更加符合单一设计/职责原则

在Spring4.2之后官方就推荐使用构造方法注入的方式(因为它的优点).如果要传入太多参数就需要考虑单一设计原则问题了.

但是我们在开发的时候依然会使用属性注入的方式,因为写法很简便.

@AutoWired来源

@AutoWired注解是来自于Spring的,也就是来自于IOC容器,换句话说,@AutoWired注解只支持spring框架,不能在其他框架使用@AutoWired

@AutoWired方法参数

@AutoWired与@Resource_第15张图片

@AutoWired就只有一个required的参数.

required参数 : 设置为true的时候认为可以自动注入 ,false就是关闭自动注入

@AutoWired注解作用范围

这个源码可以看的出来.

@AutoWired与@Resource_第16张图片

根据源码可以看的出来,@AutoWired注解支持构造方法,成员变量,成员方法以及注解上..

@AutoWired与@Resource的区别

  • 来源不同

@AutoWired注解来自于Spring,只支持Spring框架,不能在其他框架中使用

@Resource注解是JDK提供的遵循JSR-250规范,可以适用于所有的Java框架

  • 装配顺序不同

@AutoWired默认装配顺序是先按照类型进行匹配,如果匹配了多个Bean就在按照名称进行匹配,如果没有找到或者匹配到多个就会抛出异常,如果期间配置了@Qualifier注解就会按照它的参数进行匹配,如果匹配到了则进行自动装配,没有匹配就抛出异常

@Resource注解默认的装配顺序是先按照名称进行匹配,如果没有匹配或者匹配多个,则按照类型进行匹配,如果还没有匹配到或者匹配出多个则抛出异常.如果指定name则按照name进行唯一匹配,如果指定type则按照type进行唯一匹配,没有匹配到就抛出异常,如果既指定name也指定type那么就按照name和type进行唯一匹配,匹配到了则自动装配,没有匹配到则抛出异常.

  • 方法的参数不同

@AutoWired注解只有一个required参数,表示是否开启自动注入

@Resource注解有多个方法参数,最重要的2个参数是name和type

  • 注解应用的范围不同

@AutoWired注解可以加在成员变量,成员方法,方法参数及注解上

@Resource注解可以加在 类,成员变量,方法上.

  • 依赖注入的方式不同

@AutoWired注解支持属性注入,setter注入,构造方法注入

@Resource注解支持属性注入,setter注入,但是不支持构造方法注入

@Qualifier

Qualifier意思是合格者,一般跟Autowired配合使用,需要指定一个bean的名称,通过bean名称就能找到需要装配的bean。

我们一般是使用@AutoWired进行Bean的注入的,但是当有同一个类型多个Bean的时候,Spring就会抛出异常NoUniqueBeanDefinitionException

如下 :

我们就可以使用注解@Qualifier注解中填入我们想要装配Bean的名称,所以,通过将 @Qualifier 注解与我们想要指定特定的Bean名称一起装配,这样Spring就会从多个相同类型并满足装配的要求找出我们想要的Bean

如果@Primary和@Qualifier注解都在那么会优先执行@Qualifier

@primary

当我们使用自动配置的方式装配Bean时,如果这个Bean有多个候选者,假如其中一个候选者具有@Primary注解修饰,该候选者会被选中,作为自动配置的值。

如果@Primary和@Qualifier注解都在那么会优先执行@Qualifier

解决同一类型Bean报错的问题

使用Resource注解解决

使用Resource注解来解决上述问题,并仔细讲解Resource注解

@AutoWired与@Resource_第17张图片

使用@AutoWired注解 + @Qualifier注解解决

Qualifier意思是合格者,一般跟Autowired配合使用,需要指定一个bean的名称,通过bean名称就能找到需要装配的bean。

@AutoWired与@Resource_第18张图片

使用@primary注解解决

当我们使用自动配置的方式装配Bean时,如果这个Bean有多个候选者,假如其中一个候选者具有@Primary注解修饰,该候选者会被选中,作为自动配置的值。

@AutoWired与@Resource_第19张图片

你可能感兴趣的:(Spring,JavaEE,spring,java)