qidao123.com技术社区-IT企服评测·应用市场

标题: 聊聊@Autowired与@Resource的区别 [打印本页]

作者: 涛声依旧在    时间: 2025-4-28 10:12
标题: 聊聊@Autowired与@Resource的区别
1. 前言

从事过很多家公司,见过很多项目,发现@Autowired和@Resource的使用都是一样的乱,
一个项目中有使用@Autowired的,有使用@Resource的,
甚至有的类中一会儿使用@Autowired,一会儿使用@Resource,固然不影响业务功能的实现,但看起来真的是杂乱无章。
本篇博客主要解说这2个注解之间的区别。
2. 来源不同

@Autowired是Spring框架的注解。
@Resource是Java的注解(来自于JSR-250),由Spring框架兼容支持。
说明:JSR是Java Specification Requests的缩写,意思是Java规范提案。
3. 依靠查找顺序不同

@Autowired先根据类型查找,如果存在多个Bean,再根据名称查找。
@Resource先根据名称查找,如果查找不到,再根据类型查找。
3.1 验证@Autowired先根据类型查找,再根据名称查找

起首,新建接口:
  1. public interface NotificationService {
  2.     void send();
  3. }
复制代码
然后新建第一个实现类:
  1. import org.springframework.stereotype.Service;
  2. @Service
  3. public class EmailService implements NotificationService {
  4.     @Override
  5.     public void send() {
  6.         System.out.println("发送邮件通知");
  7.     }
  8. }
复制代码
接着新建第二个实现类:
  1. import org.springframework.stereotype.Service;
  2. @Service
  3. public class SmsService implements NotificationService {
  4.     @Override
  5.     public void send() {
  6.         System.out.println("发送短信通知");
  7.     }
  8. }
复制代码
最后新建Controller,并使用@Autowired来注入NotificationService:
  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.web.bind.annotation.RestController;
  3. @RestController("/dependency/injection/test")
  4. public class NotificationController {
  5.     @Autowired
  6.     private NotificationService notificationService;
  7. }
复制代码
此时启动项目,会抛出org.springframework.beans.factory.NoUniqueBeanDefinitionException非常,
缘故原由是因为有2个NotificationService类型的Bean,Spring不确定注入哪一个Bean,这也证明@Autowired默认是先根据类型查找。
有三种解决方案可以解决该题目,
第一种解决方案是使用@Primary注解:
  1. import org.springframework.context.annotation.Primary;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. @Primary
  5. public class EmailService implements NotificationService {
  6.     @Override
  7.     public void send() {
  8.         System.out.println("发送邮件通知");
  9.     }
  10. }
复制代码
说明:如果有多个同类型的Bean,Spring会优先使用@Primary注解标志的Bean。
第二种解决方案是修改字段名称:
  1. @Autowired
  2. private NotificationService emailService;
复制代码
第三种解决方案是使用@Qualifier注解:
  1. @Autowired
  2. @Qualifier("emailService")
  3. private NotificationService notificationService;
复制代码
第二种解决方案和第三种解决方案证明@Autowired是根据名称查找的,
两者的区别是第二种解决方案是按字段名称查找的(隐式),第三种解决方案是按指定的名称查找的(显式)。
3.2 验证@Resource先根据名称查找,再根据类型查找

起首,新建接口:
  1. public interface NotificationService {
  2.     void send();
  3. }
复制代码
然后新建第一个类(注意事项:不是实现类):
  1. import org.springframework.stereotype.Service;
  2. @Service
  3. public class EmailService {
  4.     public void send() {
  5.         System.out.println("发送邮件通知");
  6.     }
  7. }
复制代码
接着新建第二个类(注意事项:是实现类):
  1. import org.springframework.stereotype.Service;
  2. @Service
  3. public class SmsService implements NotificationService {
  4.     @Override
  5.     public void send() {
  6.         System.out.println("发送短信通知");
  7.     }
  8. }
复制代码
最后新建Controller,并使用@Resource来注入NotificationService:
  1. import org.springframework.web.bind.annotation.RestController;
  2. import javax.annotation.Resource;
  3. @RestController("/dependency/injection/test")
  4. public class NotificationController {
  5.     @Resource
  6.     private NotificationService emailService;
  7. }
复制代码
此时启动项目,会抛出org.springframework.beans.factory.BeanNotOfRequiredTypeException非常,
缘故原由是因为按字段名称查找到的EmailService Bean,不是NotificationService类型,这也证明@Resource默认是先根据名称查找。
有两种解决方案可以解决该题目,
第一种解决方案是显式指定Bean名称:
  1. @Resource(name = "smsService")
  2. private NotificationService emailService;
复制代码
第二种解决方案是修改字段名称:
  1. @Resource
  2. private NotificationService notificationService;
复制代码
第二种解决方案能注入乐成,也证明@Resource是根据类型查找的,
此时因为NotificationService只有一个实现类SmsService,以是直接注入乐成,
如果将EmailService也改为NotificationService的实现类:
  1. import org.springframework.stereotype.Service;
  2. @Service
  3. public class EmailService implements NotificationService {
  4.     @Override
  5.     public void send() {
  6.         System.out.println("发送邮件通知");
  7.     }
  8. }
复制代码
那么启动项目,会抛出org.springframework.beans.factory.NoUniqueBeanDefinitionException非常。
4. 参数不同

@Autowired只有1个required参数,@Resource有name、type等7个参数。
4.1 @Autowired的参数

@Autowired只有1个参数,如下所示:
  1. public @interface Autowired {
  2.     boolean required() default true;
  3. }
复制代码
默认环境下,@Autowired要求依靠必须存在,可以通过required = false设置为可选。
  1. @Autowired(required = false)
  2. private NotificationService notificationService;
复制代码
4.2 @Resource的参数

@Resource有7个参数,如下所示:
  1. public @interface Resource {
  2.     String name() default "";
  3.     String lookup() default "";
  4.     Class<?> type() default java.lang.Object.class;
  5.     enum AuthenticationType {
  6.             CONTAINER,
  7.             APPLICATION
  8.     }
  9.     AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
  10.     boolean shareable() default true;
  11.     String mappedName() default "";
  12.     String description() default "";
  13. }
复制代码
默认环境下,@Resource先根据字段名查找Bean,可以通过name参数显式指定名称,通过type参数显式指定类型。
  1. @Resource(name = "emailService", type = NotificationService.class)
  2. private NotificationService notificationService;
复制代码
5. 支持的依靠注入方式不同

@Autowired支持字段注入、Setter方法注入和构造函数注入。
@Resource支持字段注入、Setter方法注入,不支持构造函数注入。
5.1 @Autowired支持的依靠注入方式

1)字段注入:
  1. @RestController("/dependency/injection/test")
  2. public class NotificationController {
  3.     @Autowired
  4.     private NotificationService notificationService;
  5. }
复制代码
这种方式不推荐使用,但在现实项目中使用的最多。
2)Setter方法注入:
  1. @RestController("/dependency/injection/test")
  2. public class NotificationController {
  3.     private NotificationService notificationService;
  4.     @Autowired
  5.     private void setNotificationService(NotificationService notificationService) {
  6.         this.notificationService = notificationService;
  7.     }
  8. }
复制代码
3)构造函数注入
  1. @RestController("/dependency/injection/test")
  2. public class NotificationController {
  3.     private final NotificationService notificationService;
  4.     public NotificationController(NotificationService notificationService) {
  5.         this.notificationService = notificationService;
  6.     }
  7. }
复制代码
这种方式是Spring官方推荐的首选方式。
5.2 @Resource支持的依靠注入方式

1)字段注入:
  1. @RestController("/dependency/injection/test")
  2. public class NotificationController {
  3.         @Resource
  4.     private NotificationService notificationService;
  5. }
复制代码
2)Setter方法注入:
  1. @RestController("/dependency/injection/test")
  2. public class NotificationController {
  3.     private NotificationService notificationService;
  4.         @Resource
  5.     private void setNotificationService(NotificationService notificationService) {
  6.         this.notificationService = notificationService;
  7.     }
  8. }
复制代码
@Resource不支持构造函数注入,如果在构造函数上使用@Resource注解,IDEA会提示:
'@Resource' not applicable to constructor。
6. 总结

@Autowired和@Resource都是用来实现依靠注入的注解,但两者之间是有区别的,主要有以下4点:
文章持续更新,欢迎关注微信公众号「申城异乡人」第一时间阅读!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4