平时开发中,我们知道,spring中,@Resource和@Autowired都是可以在bean的注入时使用。这里简单介绍一下@Resource和@Autowired注解:
- @Resource有两个常用属性name、type,注入时分4种情况:
- 指定name和type:通过name找到唯一的bean,找不到抛出异常;如果type和字段类型不一致,也会抛出异常;
- 指定name:通过name找到唯一的bean,找不到抛出异常;
- 指定type:通过tpye找到唯一的bean,如果不唯一,则抛出异常;
- 都不指定:通过字段名作为key去查找,找到则赋值;找不到则再通过字段类型去查找,如果不唯一,则抛出异常。
- @Autowired只有一个属性required,默认值为true,为true时,找不到就抛异常,为false时,找不到就赋值为null
- @Autowired按类型查找,如果该类型的bean唯一,直接注入,如果不唯一,并不一定会报错,而是按照字段名字推断选择哪个bean;可通过注解@Qualifier配合使用解决,也可以指定字段名称和实例名称一致,这时不需要借助@Qualifier注解。
不过它们之间有什么区别呢,下面先用代码演示一下,为了方便演示,这个快速创建一个spring boot项目,项目结构如下:
为了测试,创建一个空的TestService文件:
public class TestService {
}
在TestConfig中,生成两个TestService的实例对象:
@Configuration
public class TestConfig {
@Bean
//@Bean("firstService")
public TestService firstService() {
return new TestService();
}
@Bean
//@Bean("secondService")
public TestService secondService() {
return new TestService();
}
}
注意:使用@Bean注解,不指定生成实例名称时,默认就是方法名。
下面进行测试:
首先测试@Resource注解:
- 测试字段名称和实例名称不符(不指定):
@SpringBootTest
class SpLearnResourceAndAutowiredApplicationTests {
@Resource
private TestService testService1;
@Resource
private TestService testService2;
@Test
void contextLoads() {
System.out.println("done!");
}
}
测试结果,出现异常:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.learn.service.TestService' available: expected single matching bean but found 2: FirstService,secondService
- 测试字段名称和实例名称不符(指定):
@SpringBootTest
class SpLearnResourceAndAutowiredApplicationTests {
@Resource(name = "firstService")
private TestService testService1;
@Resource(name = "secondService")
private TestService testService2;
@Test
void contextLoads() {
System.out.println("done!");
}
}
测试结果,未出现异常:
done!
- 测试字段名称和实例名称相同:
@SpringBootTest
class SpLearnResourceAndAutowiredApplicationTests {
@Resource
private TestService firstService;
@Resource
private TestService secondService;
@Test
void contextLoads() {
System.out.println("done!");
}
}
测试结果,未出现异常:
done!
接着,测试一下@Autowired注解:
- 测试字段名称和实例名称不符(不指定):
@SpringBootTest
class SpLearnResourceAndAutowiredApplicationTests {
@Autowired
private TestService testService1;
@Autowired
private TestService testService2;
@Test
void contextLoads() {
System.out.println("done!");
}
}
测试结果,出现异常:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.learn.service.TestService' available: expected single matching bean but found 2: firstService,secondService
- 测试字段名称和实例名称不符(指定),此时@Autowired需要跟 @Qualifier注解配合使用:
@SpringBootTest
class SpLearnResourceAndAutowiredApplicationTests {
@Qualifier("firstService")
@Autowired
private TestService testService1;
@Qualifier("secondService")
@Autowired
private TestService testService2;
@Test
void contextLoads() {
System.out.println("done!");
}
}
测试结果,未出现异常:
done!
- 测试字段名称和实例名称相同:
@SpringBootTest
class SpLearnResourceAndAutowiredApplicationTests {
@Autowired
private TestService firstService;
@Autowired
private TestService secondService;
@Test
void contextLoads() {
System.out.println("done!");
}
}
测试结果,未出现异常:
done!
通过以上测试结果和其他搜集的资料,总结一下@Resource注解和@Autowired注解的相同点和不同点:
相同点:
- Spring中都可以使用;
- 都可以作用在字段和setter方法上;
- 当字段名称和实例名称相同时,两者作用相似。
不同点:
- @Resource是JDK提供的,而@Autowired是Spring提供的;
- @Resource不允许找不到bean的情况,而@Autowired允许(@Autowired(required = false));
- 指定name的方式不一样,@Resource(name = “beanName”),@Autowired需要借助@Qualifier(“beanName”)注解;
- @Resource默认通过name查找,找不到则通过字段类型去查找,而@Autowired默认通过type查找,如果找到的bean不唯一,则再通过字段名称推断相应的bean。