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点:

  1. 来源不同

    @Autowired是Spring框架的注解。

    @Resource是Java的注解(来自于JSR-250),由Spring框架兼容支持。

  2. 依赖查找顺序不同

    @Autowired先根据类型查找,如果存在多个Bean,再根据名称查找。

    @Resource先根据名称查找,如果查找不到,再根据类型查找。

  3. 参数不同

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

  4. 支持的依赖注入方式不同

    @Autowired支持字段注入、Setter方法注入和构造函数注入。

    @Resource支持字段注入、Setter方法注入,不支持构造函数注入。

文章持续更新,欢迎关注微信公众号「申城异乡人」第一时间阅读!

聊聊@Autowired与@Resource的区别的更多相关文章

  1. java @Autowired与@Resource的区别

    @Autowired与@Resource的区别     1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上. 2.@Autowired默认 ...

  2. Spring 注释 @Autowired 和@Resource 的区别

    Spring 注释 @Autowired 和@Resource 的区别 一. @Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上. 二. @Autowired ...

  3. @Autowired 与@Resource的区别(详细)

    参考:@Autowired 与@Resource的区别(详细) spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource.@Pos ...

  4. java面试题之@Autowired和@Resource的区别

    @Autowired和@Resource的区别: 1.都可以用来装配bean,都可以写在字段或者方法上: 2. @Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果允许为nul ...

  5. @Autowired 与@Resource的区别详解

    spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource.@PostConstruct以及@PreDestroy. @Resour ...

  6. 关于@Autowired和@Resource注解区别

    区分一下@Autowired和@Resource两个注解的区别: 1.@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配 2.@A ...

  7. @Autowired 与@Resource的区别

    1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上. 2  @Autowired默认按类型装配(这个注解是属业spring的),默认情况下 ...

  8. @Autowired与@Resource的区别

    1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上. 2.@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必 ...

  9. spring @Autowired或@Resource 的区别

    1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上. 2.@Autowired默认按类型装配(这个注解是属于spring的),默认情况下必 ...

  10. Spring中@Autowired与@Resource的区别

    1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上. 2.@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必 ...

随机推荐

  1. Windows下安装和配置Java JDK

    1.下载地址 JDK21 Windows安装版下载地址:https://www.oracle.com/java/technologies/downloads/#jdk21-windows JDK21 ...

  2. Zabbix Agent 安装配置

    1 介绍 zabbix([`zæbiks])是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案.    zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵活 ...

  3. SCCPC2024 游记

    打了一堆板子,一个都没用上. 队友:zhicheng,nityacke 开场发现 H 是签到,NIT 签了.然后盯 F(圆向某个方向运动,问存不存在一个时刻使得全在长方形之内),发现不外乎一堆二次方程 ...

  4. java连接mysql遇到sql执行错误,异常判断和抛出源码分析

    一.代码处理过程

  5. DeepSeek+Zotero

    技术背景 在DeepSeek系列文章中,我们已经分别介绍过关于DeepSeek在Ubuntu Linux平台和Windows平台上的本地部署方案,以及Ollama.ChatBox和AnythingLL ...

  6. 用python做时间序列预测三:时间序列分解

    在初始概念篇中,我们简单提到了时间序列由趋势.周期性.季节性.误差构成,本文将介绍如何将时间序列的这些成分分解出来.分解的使用场景有很多,比如当我们需要计算该时间序列是否具有季节性,或者我们要去除该时 ...

  7. WPF Expander style

    <!--ExpanderStyle--> <Style x:Key="ExpanderStyleOne" TargetType="{x:Type Exp ...

  8. Typecho复制文章自带版权说明

    自带版权说明代码 <script> document.body.addEventListener('copy', function (e) { if (window.getSelectio ...

  9. 【渗透测试】Vulnhub DarkHole

    渗透环境 攻击机:   IP: 192.168.216.129(Kali) 靶机:     IP:192.168.216.130 靶机下载地址:https://www.vulnhub.com/entr ...

  10. AI 大模型:现状、挑战与未来多维度发展趋势

    在科技浪潮的推动下,以 Deepseek 为代表的 AI 大模型正以颠覆性力量重塑产业格局.从金融风控到工业质检,从智慧医疗到智能教育,这些轻量化的 AI 工具不仅打破了传统工作模式的桎梏,更构建起一 ...