参考 :
@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)是唯一的.
当我们运行的时候会发生什么呢???
什么办法可以解决呢 ?
最简单最直接的办法就是,你在存储一个名称为user的Bean,或者将一个Bean的名称修改为Bean.
如果我非要使用那三个其中一个Bean呢?该怎么办?
有两种方法 :
- 第一种方法 : 使用Resource注解使用自带的name参数来指定使用的Bean名称
- 第二种方法 : 使用AutoWired注解注入,并且使用Qualifier来进行筛选
- 第三种方法 : 使用primary注解
我先分别讲解这几个注解,然后在来解决这个问题
@Resource注解
@Resource的查找顺序
既指定name又指定type
如果既指定name又指定type,他就会在Spring查找name和type唯一匹配的bean,如果没有找到就会抛出异常.
只指定name
如果只指定了name的情况,他就会在Spring中查找name唯一匹配的bean,如果找到了则自动装配,没有找到则抛出异常,
只指定type
如果只指定了type,那么在Spring中查找type唯一匹配的bean,如果没有找到就抛出异常.
既没有指定name,也没有指定type
好我们在来整体总结一下 :
依赖注入的功能,是通过先在 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注解实现属性注入
@Resource注解实现setter注入
@Resource注解并不能实现构造方法注入
@Resource注解不能实现构造方法注入,原因是Resource的执行时机比构造方法执行时机晚一些.
@Resource的来源
@Resource是JDK提供的一个注解,遵循JSR-250规范(Java 250 规范提案.
所以@Resource注解适用于所有的Java框架
@Resource的方法参数
@Resource注解提供多个参数,最重要的就是name和type.
@Resource注解的应用范围
@AutoWired
@AutoWired注解也是可以将依赖的对象注入到当前对象中.
我们接下来详细分析一下@AutoWired重要的几点
@AutoWired查找顺序
@AutoWired默认是先按照类型进行匹配Bean,如果匹配了多个Bean就按照name进行匹配,如果还是匹配了多个Bean就会抛出异常.
我们仔细分析@AutoWired的装配顺序
- 首先先会按照类型进行匹配,如果匹配到了一个唯一Bean就进行自动装配,如果没有匹配到则抛出异常
- 如果根据类型匹配出多个Bean,就看是否配置了@Qualifier注解
- 如果没有配置,则默认会按照名称进行匹配,如果查找到了,则会进行自动装配,如果没有查找到就会抛出异常
- 如果配置了@Qualifier注解则会根据它的参数的名称进行匹配,如果匹配到了则进行自动装配,否则就会抛出异常
@AutoWired依赖注入方式
使用@AutoWired可以实现三种注入,属性注入,setter注入,构造方法注入.
属性注入
@Autowired //使用一个AutoWired这样的一个注解---->自动装配的意思 private UserService userService;//UserService成员属性
属性注入的优点和缺点
优点 :
- 属性注入只需要在属性上加一个@AutoWired注解,写法简便,可读性高,易维护.
缺点 :
- 1.不能注入final修饰的属性.
为啥呢 ?
- 因为我们知道JDK是我们最底层的框架,spring是上层,使用spring也要依赖java的,所以要遵循Java的规范,Java固定被final修饰的属性1.在定义的时候就进行赋值 2.在构造方法内部进行赋值.
所以,是因为不满足Java的规范
- 2.属性注入只能在IOC容器才能使用(类与IOC容器高度耦合),使用其他容器/框架的时候不能使用属性注入(通用性不好)
- 3.更容易违背单一职责原则
啥是单一职责原则呢 ?
单一职责原则的核心思想 : 一个类最好只做一件事,只有一个引起它变化的原因
换句话说,类只有单一功能,不要为类实现过多的功能点,以保证实体只有一个引起职责变化的原因
一个类只做一件事,要么做A事情,要么做B事情.只做一件事情
为什么说属性注入更容易违背单一职责原则呢 ?
- 由于属性注入使用起来简便,这样就更容易使得开发者在类中注入多个对象,就可能会导致滥用的概率大大提高,所以违背单一职责原则的概率就大大提高-->更容易违背 不是一定违背,
setter注入
Setter注入的优缺点
优点 :
- setter注入满足单一设计/职责原则.
因为setter方法的特性,一个setter方法只对应一个对象,不会有注入多个对象的可能性,所以满足单一设计/职责原则
缺点 :
- 不能注入final修饰的对象
还是与属性注入的解释是一样的,原因就是JDK是我们最底层的框架,Spring作为上层,要基于JDK/Java的,所以要满足Java的规范,java规定,被final修饰的属性1.在定义的时候进行赋值2.在构造方法内部进行赋值
- 注入的对象可能会被修改
由于setter方法是可以被多次调用的,有修改的风险,所以注入的对象就可能被修改.
构造方法注入
构造方法注入的优缺点
优点 :
构造方法最牛,上面的缺点,都是俺构造方法的优点.
就比如,属性注入和setter注入都不能解决注入final修饰的属性问题,那对于构造方法注入就能够解决
- 能够注入final修饰的属性
为什么构造方法可以注入final修饰的属性呢?
原因还是一样的,因为满足Java的规范,被final修饰的属性 一个是定义的时候就进行赋值,一个是在构造方法内部进行赋值.满足第二条,所以可以注入final修饰的属性.
- 注入的对象不会被修改.
构造方法注入 注入的对象不会被修改,因为构造方法只会执行一次.
- 构造方法注入是完全初始化的.
因为依赖注入是在构造方法内部执行的,而构造方法又是在类起初创建的时候就执行的,所以会被完全初始化
- 它的通用性会更好
构造方法注入因为基于java的,JDK是最底层框架,所以无论在哪一个容器/框架都可以适用
缺点 :
- 构造方法可以注入多个对象,也就违背了单一设计原则
- 写法不简便
官方建议
在Spring4.2之前推荐的注入用法就是setter注入,因为setter注入更加符合单一设计/职责原则
在Spring4.2之后官方就推荐使用构造方法注入的方式(因为它的优点).如果要传入太多参数就需要考虑单一设计原则问题了.
但是我们在开发的时候依然会使用属性注入的方式,因为写法很简便.
@AutoWired来源
@AutoWired注解是来自于Spring的,也就是来自于IOC容器,换句话说,@AutoWired注解只支持spring框架,不能在其他框架使用@AutoWired
@AutoWired方法参数
@AutoWired就只有一个required的参数.
required参数 : 设置为true的时候认为可以自动注入 ,false就是关闭自动注入
@AutoWired注解作用范围
这个源码可以看的出来.
根据源码可以看的出来,@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注解 + @Qualifier注解解决
Qualifier意思是合格者,一般跟Autowired配合使用,需要指定一个bean的名称,通过bean名称就能找到需要装配的bean。
使用@primary注解解决
当我们使用自动配置的方式装配Bean时,如果这个Bean有多个候选者,假如其中一个候选者具有@Primary注解修饰,该候选者会被选中,作为自动配置的值。