@Autowired
和@Resource
都是Spring
项目中用于进行依赖注入的注解,它们的区别是什么?
注解来源不一样
@Resource
是JavaEE提供的,在javax.annotation
包中去定义的。
@Autowired
是Spring框架提供的,专门用于自动装配 Spring
容器中的 Bean
。
装配方式不一样
@Resource
@Resource
默认根据名称去寻找容器中的对象,如果名称不存在,才根据类型去寻找。
假如我有一个Jiejie和JiejieSon的对象,它们都实现了IJiejie接口
IJiejie接口
public interface IJiejie {
}
Jiejie类
@Service
public class Jiejie implements IJiejie{
}
JiejieSon类
@Service
public class JiejieSon implements IJiejie{
}
接着我定义了一个TestService类来测试
TestService
@Component
public class TestService implements CommandLineRunner {
@Resource
private Jiejie jiejieSon;
@Override
public void run(String... args) throws Exception {
System.out.println(jiejieSon);
}
}
我的类型是Jiejie
,然后名称是jiejieSon
,由于是@Resource
注解,然后它是默认根据名称去寻找的,jiejieSon是能找到的,即JiejieSon,然而我却用Jiejie去接收,类型不一样,运行之后会报错,启动后果然出现了错误。
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named ‘jiejieSon’ is expected to be of type ‘com.itheima.pojo.Jiejie’ but was actually of type ‘com.itheima.pojo.JiejieSon’
引起的原因:org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为 ‘jiejieSon’ 的 Bean 期望为 ‘com.itheima.pojo.Jiejie’ 类型,但实际为 ‘com.itheima.pojo.JiejieSon’ 类型。
如果名称找不到,会根据类型去寻找,比如我将jiejieSon
改为jiejieSon1
,因为JiejieSon1
对象是不存在的,这个时候会根据类型寻找,且不会报错
@Component
public class TestService implements CommandLineRunner {
@Resource
private Jiejie jiejieSon1;
@Override
public void run(String... args) throws Exception {
System.out.println(jiejieSon1);
}
}
控制台输出为com.itheima.pojo.Jiejie@15b0d4d4
,说明名称找不到,使用了类型去寻找。
@Autowired
@Autowired
默认会根据类型去寻找,如果类型有多个实现的时候,再根据名称去查找。
还是之前的例子,但我把注解换成了@Autowired
@Component
public class TestService implements CommandLineRunner {
@Autowired
private Jiejie jiejieSon;
@Override
public void run(String... args) throws Exception {
System.out.println(jiejieSon);
}
}
这份代码中在@Resource
的实验中是报错的,但在这里是正常运行,启动后控制台输出
com.itheima.pojo.Jiejie@67d90a8b
,因为默认根据类型寻找。
假如我有多个实现的时候,这个时候根据名称寻找。
前面有提到过,我定义了一个IJiejie
的接口,而Jiejie
和JiejieSon
都实现了它。
@Component
public class TestService implements CommandLineRunner {
@Autowired
private IJiejie jiejieSon;
@Override
public void run(String... args) throws Exception {
System.out.println(jiejieSon);
}
}
上面这份代码中,因为IJiejie
有多个实现,根据名称寻找,jiejieSon
通过名称寻找则会找到JiejieSon
这个对象,控制台输出com.itheima.pojo.JiejieSon@67d90a8b
下面这份代码,我改成了jiejie
,根据名称寻找到Jiejie
对象,控制台输出com.itheima.pojo.Jiejie@67d90a8b
@Component
public class TestService implements CommandLineRunner {
@Autowired
private IJiejie jiejie;
@Override
public void run(String... args) throws Exception {
System.out.println(jiejie);
}
}
好,那么如果我写的既不是jiejie
也不是jiejieSon
,而是写成jiejie1
,这会出现什么问题,由于根据名称去寻找,它想找的是Jiejie1
对象,然而并没有,因此会报错
@Component
public class TestService implements CommandLineRunner {
@Autowired
private IJiejie jiejie1;
@Override
public void run(String... args) throws Exception {
System.out.println(jiejie1);
}
}
***************************
APPLICATION FAILED TO START
***************************
Description:
Field jiejie1 in com.itheima.Serivce.TestService required a single bean, but 2 were found:
- jiejie: defined in file [D:\IntelliJ IDEA\Project\Project\tlias-management\target\classes\com\itheima\pojo\Jiejie.class]
- jiejieSon: defined in file [D:\IntelliJ IDEA\Project\Project\tlias-management\target\classes\com\itheima\pojo\JiejieSon.class]
This may be due to missing parameter name information
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
Ensure that your compiler is configured to use the '-parameters' flag.
You may need to update both your build tool settings as well as your IDE.
(See https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#parameter-name-retention)
这个报错翻译为:
***************************
应用程序启动失败
***************************
描述:
com.itheima.Serivce.TestService 中的字段 jiejie1 需要一个单一的 Bean,但找到 2 个:
- jiejie:定义在文件 [D:\IntelliJ IDEA\Project\Project\tlias-management\target\classes\com\itheima\pojo\Jiejie.class]
- jiejieSon:定义在文件 [D:\IntelliJ IDEA\Project\Project\tlias-management\target\classes\com\itheima\pojo\JiejieSon.class]
这可能是由于缺少参数名称信息导致的
操作:
考虑将其中一个 Bean 标记为 @Primary,更新消费者以接受多个 Bean,或使用 @Qualifier 来识别应该被消费的 Bean
确保您的编译器配置使用 '-parameters' 标志。
您可能需要更新构建工具设置以及您的 IDE。
(请参阅:https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#parameter-name-retention)
要解决这个问题,我们可以配合@Qualifier
去使用
@Component
public class TestService implements CommandLineRunner {
@Autowired
@Qualifier("jiejieSon")
private IJiejie jiejie1;
@Override
public void run(String... args) throws Exception {
System.out.println(jiejie1);
}
}
控制台输出com.itheima.pojo.JiejieSon@73fdecc0