@Autowired和@Resource的注入过程/区别
目录
2.2.2 ByType>>>autowireCandidate>>>ByName
2.2.2 ByType>>>autowireCandidate>>>Qualifier>>>ByName
2.2.4 ByType>>>autowireCandidate>>>Qualifier>>>Primary>>>ByName
1 前言
@Autowired注解和@Resource注解都是我们在开发中常用的注解,但是大家可以发现,有些人自动注入的时候用@Autowired,有的人用了@Resource,那么它们有什么区别呢?那么什么时候用@Autowired什么时候用@Resource呢?
首先先说明下,@Autowired注解默认是按照type注入的,而@Resource注解默认是按照name注入的。那么我们就通过小demo来演示下。
2 demo演示
2.1 @Autowired注解
2.1.1 ByType>>>ByName
配置两个单例bean:OrderServcice和UserServcice,在UserService中注入OrderServcie
单例bean:OrderService
@Component
public class OrderService {
}
单例bean:UserService
@Component
public class UserService {
@Autowired
private OrderService orderService;
}
再配置两个orderService类型的bean:orderService1和orderService2
@ComponentScan("com.liubujun")
public class AppConfig {
@Bean
public OrderService orderService1(){
return new OrderService();
}
@Bean
public OrderService orderService2(){
return new OrderService();
}
}
测试类:
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(applicationContext.getBean("orderService"));
}
测试结果:

测试显示可以正常注入成功。这个时候有人可能就要问了。这说与不说有什么区别吗?我们都知道@ Autowired注解是先根据类型找,然后在根据属性名字找啊,这里先根据类型找找到了OrderService类型的有3个(OrderService,OrderService1,OrderService2),然后在根据名字找自己定义的orderService从而找到了这不是很正常。其实这中间的过程并没有那么简单。其实中间还会去判断是不是自动填充的候选者(autowireCandidate())默认是true.
2.2.2 ByType>>>autowireCandidate>>>ByName
之前说了@Autowired注解其实属性注入时并不是直接进行type完成之后,就直接根据name进行判断,中间还要判断是否是自动填充的候选者,这个属性有默认值,默认值是true。
boolean autowireCandidate() default true;
进行测试,我们将之前的普通bean进行修改,如下:
@ComponentScan("com.liubujun")
public class AppConfig {
@Bean(autowireCandidate = false)
public OrderService orderService1(){
return new OrderService();
}
@Bean
public OrderService orderService2(){
return new OrderService();
}
}
属性注入改成注入orderService1如下:
@Component
public class UserService {
@Autowired
private OrderService orderService1;
}
再次进行测试结果:报错结果如下
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'orderService1'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.liubujun.service.OrderService' available: expected single matching bean but found 2: orderService,orderService2
原因解释如下:
属性注入时先根据type去找,找到了OrderService类型的有3个(OrderService,OrderService1,OrderService2)。然后根据是否是自动填充的候选者进行筛选,发现nam为OrderService1上的属性autowireCandidate为false,那么就剩下两个OrderService类型的有2个(OrderService,OrderService2),再根据name去匹配,发现没有name为OrderService1的属性,于是就报错了。
2.2.2 ByType>>>autowireCandidate>>>Qualifier>>>ByName
除此之外,属性注入的过程还会有一个分组的概念,可以经过Qualifier进行分组。例如:
对orderService1进行分组xxx的分组,然后注入的时候也进行分组,这个时候即使属性名称不一样也不会进行报错,修改代码如下:
@ComponentScan("com.liubujun")
public class AppConfig {
@Bean
@Qualifier("xxx")
public OrderService orderService1(){
return new OrderService();
}
@Bean
public OrderService orderService2(){
return new OrderService();
}
}
@Component
public class UserService {
@Autowired
@Qualifier("xxx")
private OrderService orderService111;
}
启动测试类:发现不会报错

分析如下:
属性注入时先根据type去找,找到了OrderService类型的有3个(OrderService,OrderService1,OrderService2)。然后根据是否是自动填充的候选者进行筛选,发现都是true(默认都是true),再看是否有进行Qualifier分组,有的话就根据分组name名称去找。找到了xxx,然后就正常输出。
2.2.4 ByType>>>autowireCandidate>>>Qualifier>>>Primary>>>ByName
以上经过筛选之后,可能一个类型下还有多个bean,那么通过加一个@Primary注解,让该bean成为主bean。那么即使注入的名称不一样也不会报错。代码修改如下:
@ComponentScan("com.liubujun")
public class AppConfig {
@Bean
@Primary
public OrderService orderService1(){
return new OrderService();
}
@Bean
public OrderService orderService2(){
return new OrderService();
}
}
@Component
public class UserService {
@Autowired
private OrderService orderService111;
}
测试启动类正常输出:

原因分析:属性注入时先根据type去找,找到了OrderService类型的有3个(OrderService,OrderService1,OrderService2)。然后根据是否是自动填充的候选者进行筛选,发现都是true(默认都是true),再看是否有进行Qualifier分组,发现没有,再看bean上面是否有Primary注解如果有,那么它就是主bean,就会将该bean赋值给需要注入的bean。
除此之外,也会通过其它的方式获取优先级最高的bean。
总结@Autowired获取bean方式如下图:

2.2 @Resource
@Resource会先根据name进行匹配,然后根据type去进行匹配,但是如果该注解上指定了name的话,没有根据name找到就会报错。修改代码如下:
@Component
public class UserService {
@Resource(name = "123")
private OrderService orderService111;
}
启动测试类,报错信息如下:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '123' available
如果指定name值,根据name去找找不到的话,就不会根据type去找了。
但如果没有指定name的话,根据name找不到,就会根据type去找了。
修改如下:
@Component
public class UserService {
@Resource
private OrderService orderService111;
}
启动测试类,依然报错。报错信息如下:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.liubujun.service.OrderService' available: expected single matching bean but found 3: orderService,orderService1,orderService2
原因如下:因为根据name去找的时候,发现没有name为orderServcice111的 类型,然后根据类型去找,但是这个时候发现却找到了3个。所以报错了,此时,将那两个普通bean注释掉就可以正常输出了。修改代码如下:
@ComponentScan("com.liubujun")
public class AppConfig {
// @Bean
// public OrderService orderService1(){
// return new OrderService();
// }
//
// @Bean
// public OrderService orderService2(){
// return new OrderService();
// }
}
测试类启动,正常输出:


浙公网安备 33010602011771号