Spring/Spring-Boot 学习 @Autowired 与 @Resource
@Autowired 和 @Resource的区别
如果在网上搜一下@Autowired 和 @Resource 的区别
, 大多数的答案都是说 @Autowired 默认按byType注入, @Resource 默认按byName注入。
首先需要理解什么叫byName, 什么叫byType。顾名思义, byName是按照名称注入,这个名称指的是什么呢?
是
Spring
容器生成bean的时候bean的名称,如果通过xml文件注入,bean的名称由 id属性确定;如果使用 配置类+注解的方式注入(@Configuration+@Bean), 则由@Bean注解标注的方法的名称确定。
byType的方式则是按照类型的方式注入,类型指的就是bean的类型的名称。
看
Spring
容器生成的bean是哪个类型的bean, 如果通过xml文件注入,bean的类型由class属性给出的全限定的类型确定;如果使用 配置类+注解的方式注入(@Configuration+@Bean), 则由@Bean注解标注的方法的返回值确定。
了解了什么是byName什么是byType, 回过头来再看网上说的这句话:
@Autowired 默认按byType注入, @Resource 默认按byName注入。
意思是说@Autowired
在注入的时候,会去容器中找类型与声明的引用的类型一样的对象来注入;而@Resource
方法,会去容器中找bean名称与声明的对象的名称一样的对象来注入。
@Resource
我们知道,其实一个类我们可以实例化多个对象,这些对象都是同一类型的。如果在容器中我们对一个类实例化了多个对象, 那么byType方法就不生效了,因为现在按照类型去容器中找对象,我们会找到多个bean
, spring
不知到要用哪个bean
。也就是说,这个时候@Autowired
注解就不会生效。事实上是只要你用的spring
版本高于3.x, @Autowired
方法一样会生效。具体的原因是@Autowired
会优先按byType
注入,如果发现容器中有多个这个类型的实例,会再按bean
的名称去匹配。具体的分析见 Spring/Spring学习 自动装配@Autowired 和 @Resource
总结一下就是:
- 在
spring 3.x
以前的版本,@Autowired
默认按byType
注入,当容器中存在多个同一type
的实例时,会报错; @Resource
默认按byName
注入;- 在
spring 3.x
及以后的版本,·@Autowired默认按
byName注入,当容器中存在多个同一
type的是实例时,会在这些实例中按
byName`挑选匹配的实例。 @Qualifier
注解可以指定@Autowired注解按@Qualifier中指定的bean名称注入。
@Autowired
@Qualifier("student01")
Student student;
下面内容转自 Autowired与@Resource的用法和区别
@Resource
@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
- 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
@Autowired与@Resource的区别
- @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
- @Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false。
- @Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,
如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
ps: @Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。