马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
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先根据类型查找,再根据名称查找
起首,新建接口:- public interface NotificationService {
- void send();
- }
复制代码 然后新建第一个实现类:- import org.springframework.stereotype.Service;
- @Service
- public class EmailService implements NotificationService {
- @Override
- public void send() {
- System.out.println("发送邮件通知");
- }
- }
复制代码 接着新建第二个实现类:- import org.springframework.stereotype.Service;
- @Service
- public class SmsService implements NotificationService {
- @Override
- public void send() {
- System.out.println("发送短信通知");
- }
- }
复制代码 最后新建Controller,并使用@Autowired来注入NotificationService:- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RestController;
- @RestController("/dependency/injection/test")
- public class NotificationController {
- @Autowired
- private NotificationService notificationService;
- }
复制代码 此时启动项目,会抛出org.springframework.beans.factory.NoUniqueBeanDefinitionException非常,
缘故原由是因为有2个NotificationService类型的Bean,Spring不确定注入哪一个Bean,这也证明@Autowired默认是先根据类型查找。
有三种解决方案可以解决该题目,
第一种解决方案是使用@Primary注解:- import org.springframework.context.annotation.Primary;
- import org.springframework.stereotype.Service;
- @Service
- @Primary
- public class EmailService implements NotificationService {
- @Override
- public void send() {
- System.out.println("发送邮件通知");
- }
- }
复制代码 说明:如果有多个同类型的Bean,Spring会优先使用@Primary注解标志的Bean。
第二种解决方案是修改字段名称:- @Autowired
- private NotificationService emailService;
复制代码 第三种解决方案是使用@Qualifier注解:- @Autowired
- @Qualifier("emailService")
- private NotificationService notificationService;
复制代码 第二种解决方案和第三种解决方案证明@Autowired是根据名称查找的,
两者的区别是第二种解决方案是按字段名称查找的(隐式),第三种解决方案是按指定的名称查找的(显式)。
3.2 验证@Resource先根据名称查找,再根据类型查找
起首,新建接口:- public interface NotificationService {
- void send();
- }
复制代码 然后新建第一个类(注意事项:不是实现类):- import org.springframework.stereotype.Service;
- @Service
- public class EmailService {
- public void send() {
- System.out.println("发送邮件通知");
- }
- }
复制代码 接着新建第二个类(注意事项:是实现类):- import org.springframework.stereotype.Service;
- @Service
- public class SmsService implements NotificationService {
- @Override
- public void send() {
- System.out.println("发送短信通知");
- }
- }
复制代码 最后新建Controller,并使用@Resource来注入NotificationService:- import org.springframework.web.bind.annotation.RestController;
- import javax.annotation.Resource;
- @RestController("/dependency/injection/test")
- public class NotificationController {
- @Resource
- private NotificationService emailService;
- }
复制代码 此时启动项目,会抛出org.springframework.beans.factory.BeanNotOfRequiredTypeException非常,
缘故原由是因为按字段名称查找到的EmailService Bean,不是NotificationService类型,这也证明@Resource默认是先根据名称查找。
有两种解决方案可以解决该题目,
第一种解决方案是显式指定Bean名称:- @Resource(name = "smsService")
- private NotificationService emailService;
复制代码 第二种解决方案是修改字段名称:- @Resource
- private NotificationService notificationService;
复制代码 第二种解决方案能注入乐成,也证明@Resource是根据类型查找的,
此时因为NotificationService只有一个实现类SmsService,以是直接注入乐成,
如果将EmailService也改为NotificationService的实现类:- import org.springframework.stereotype.Service;
- @Service
- public class EmailService implements NotificationService {
- @Override
- public void send() {
- System.out.println("发送邮件通知");
- }
- }
复制代码 那么启动项目,会抛出org.springframework.beans.factory.NoUniqueBeanDefinitionException非常。
4. 参数不同
@Autowired只有1个required参数,@Resource有name、type等7个参数。
4.1 @Autowired的参数
@Autowired只有1个参数,如下所示:- public @interface Autowired {
- boolean required() default true;
- }
复制代码 默认环境下,@Autowired要求依靠必须存在,可以通过required = false设置为可选。- @Autowired(required = false)
- private NotificationService notificationService;
复制代码 4.2 @Resource的参数
@Resource有7个参数,如下所示:- public @interface Resource {
- String name() default "";
- String lookup() default "";
- Class<?> type() default java.lang.Object.class;
- enum AuthenticationType {
- CONTAINER,
- APPLICATION
- }
- AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
- boolean shareable() default true;
- String mappedName() default "";
- String description() default "";
- }
复制代码 默认环境下,@Resource先根据字段名查找Bean,可以通过name参数显式指定名称,通过type参数显式指定类型。- @Resource(name = "emailService", type = NotificationService.class)
- private NotificationService notificationService;
复制代码 5. 支持的依靠注入方式不同
@Autowired支持字段注入、Setter方法注入和构造函数注入。
@Resource支持字段注入、Setter方法注入,不支持构造函数注入。
5.1 @Autowired支持的依靠注入方式
1)字段注入:- @RestController("/dependency/injection/test")
- public class NotificationController {
- @Autowired
- private NotificationService notificationService;
- }
复制代码 这种方式不推荐使用,但在现实项目中使用的最多。
2)Setter方法注入:- @RestController("/dependency/injection/test")
- public class NotificationController {
- private NotificationService notificationService;
- @Autowired
- private void setNotificationService(NotificationService notificationService) {
- this.notificationService = notificationService;
- }
- }
复制代码 3)构造函数注入- @RestController("/dependency/injection/test")
- public class NotificationController {
- private final NotificationService notificationService;
- public NotificationController(NotificationService notificationService) {
- this.notificationService = notificationService;
- }
- }
复制代码 这种方式是Spring官方推荐的首选方式。
5.2 @Resource支持的依靠注入方式
1)字段注入:- @RestController("/dependency/injection/test")
- public class NotificationController {
- @Resource
- private NotificationService notificationService;
- }
复制代码 2)Setter方法注入:- @RestController("/dependency/injection/test")
- public class NotificationController {
- private NotificationService notificationService;
- @Resource
- private void setNotificationService(NotificationService notificationService) {
- this.notificationService = notificationService;
- }
- }
复制代码 @Resource不支持构造函数注入,如果在构造函数上使用@Resource注解,IDEA会提示:
'@Resource' not applicable to constructor。
6. 总结
@Autowired和@Resource都是用来实现依靠注入的注解,但两者之间是有区别的,主要有以下4点:
- 来源不同
@Autowired是Spring框架的注解。
@Resource是Java的注解(来自于JSR-250),由Spring框架兼容支持。
- 依靠查找顺序不同
@Autowired先根据类型查找,如果存在多个Bean,再根据名称查找。
@Resource先根据名称查找,如果查找不到,再根据类型查找。
- 参数不同
@Autowired只有1个required参数,@Resource有name、type等7个参数。
- 支持的依靠注入方式不同
@Autowired支持字段注入、Setter方法注入和构造函数注入。
@Resource支持字段注入、Setter方法注入,不支持构造函数注入。
文章持续更新,欢迎关注微信公众号「申城异乡人」第一时间阅读!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |