聊聊@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先根据类型查找,再根据名称查找

首先,新建接口:

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方法注入,不支持构造函数注入。

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

原创作者: zwwhnly 转载于: https://www.cnblogs.com/zwwhnly/p/18851001
<think>嗯,用户想了解@Resource@Autowired注解区别,这两个在Spring中都是用来做依赖注入的。首先,我需要回忆一下这两个注解的基本特性用法。 首先,我记得@Autowired是Spring框架自己的注解,而@Resource是Java标准库里的,属于JSR-250的一部分。所以它们的来源不同,可能在使用范围上也有差异。比如,如果项目没有用Spring,可能就用不了@Autowired,但@Resource可能在别的框架里也能用。 然后,默认的注入方式。@Autowired默认是按类型(byType)来注入的,也就是根据接口或者类的类型去找匹配的Bean。而@Resource默认是按名称(byName),也就是根据Bean的名字来匹配。不过@Resource也可以指定name属性来明确使用哪个Bean,这时候可能更灵活一点。 还有,关于使用场景。如果项目里同一个接口有多个实现类,这时候用@Autowired可能需要配合@Qualifier来指定具体的Bean名称,而@Resource可以直接用name属性来指定。这样可能在某些情况下更方便。 另外,@Autowired可以用在构造器、方法、字段上,而@Resource通常用在字段方法上,构造器可能不支持?这点需要确认一下。比如,Spring的文档里有没有说@Resource不能用在构造器上? 还有required属性,@Autowired可以设置required=false,这样即使找不到Bean也不会报错,而@Resource好像没有这个属性,可能默认就是必须的,如果找不到就会报错? 然后要检查引用中的内容是否正确。比如引用2提到@Resource只能用于变量设置方法,而@Autowired可以用在构造器、变量、设置方法。所以用户可能需要知道在构造器注入时,只能用@Autowired或者@Inject这些。 还有,当有多个同类型的Bean时,@Autowired需要配合@Qualifier,而@Resource可以用name属性来解决。这种情况下,两者的使用方式不同,但都能达到目的。 还需要考虑使用场景的选择。比如,如果项目已经大量使用Spring,可能更倾向于@Autowired,因为它Spring整合得更好。而如果需要更通用的注解,或者项目中有其他JSR-250的支持,可能用@Resource更好。 另外,错误处理方面,@Autowired默认必须找到Bean,否则抛异常,而@Resource是否也是这样?根据引用3,@Autowired可以设置required=false,而@Resource可能没有这个选项,所以如果找不到的话就会直接报错,除非有默认的名称匹配。 总结一下,两者的主要区别在于来源、默认注入方式、使用位置、以及如何解决多个Bean的情况。需要把这些点整理清楚,用用户容易理解的语言表达出来,并且结合引用中的内容,确保准确性。</think>### Java Spring中@Resource@Autowired区别详解 #### 1. **来源标准支持** - **@Autowired** 是Spring框架特有的注解,仅适用于Spring容器管理的Bean。它通过类型(byType)进行依赖注入,若需按名称匹配需结合`@Qualifier`注解[^2]。 - **@Resource** 属于Java标准库(JSR-250规范),不依赖特定框架。默认按名称(byName)注入,支持通过`name`属性指定Bean名称[^2]。 #### 2. **默认注入方式** - **@Autowired** ```java @Autowired private UserService userService; // 按类型匹配 ``` 若存在多个同类型Bean,需配合`@Qualifier`指定名称: ```java @Autowired @Qualifier("userServiceImplA") private UserService userService; ``` - **@Resource** ```java @Resource private UserService userService; // 默认按字段/方法参数名匹配 ``` 也可显式指定名称: ```java @Resource(name = "userServiceImplA") private UserService userService; ``` #### 3. **使用范围** - **@Autowired** 支持**构造器、字段、设置方法(setter)**。例如构造器注入: ```java @Autowired public UserController(UserService userService) { this.userService = userService; } ``` - **@Resource** 仅支持**字段、设置方法**,**不支持构造器注入**[^2]。 #### 4. **错误处理灵活性** - **@Autowired** 默认要求依赖必须存在,否则抛出`NoSuchBeanDefinitionException`。可通过`required=false`允许注入失败: ```java @Autowired(required = false) private Optional<UserService> userService; // 依赖非必需 ``` - **@Resource** 无类似`required`属性,若未找到指定名称的Bean,直接抛出异常。 #### 5. **适用场景对比** | **场景** | **推荐注解** | **说明** | |-----------------------------|-------------------|-------------------------------------------------------------------------| | 按类型注入 | `@Autowired` | 适合单实现类或配合`@Qualifier`指定名称 | | 按名称注入 | `@Resource` | 直接通过名称匹配,代码更简洁 | | 多实现类需指定Bean | 两者均可 | `@Autowired + @Qualifier`或`@Resource(name="...")` | | 非Spring环境 | `@Resource` | 依赖Java标准库,兼容性更强 | #### 6. **代码示例对比** ```java // 使用@Autowired按类型注入 @Service public class ServiceA { @Autowired private Repository repository; } // 使用@Resource按名称注入 @Service public class ServiceB { @Resource(name = "mysqlRepository") private Repository repository; } ``` #### 总结 - **框架依赖**:`@Autowired`绑定Spring,`@Resource`框架无关。 - **注入策略**:`@Autowired`默认按类型,`@Resource`默认按名称。 - **灵活性**:`@Autowired`支持构造器注入可选依赖,`@Resource`名称控制更直接。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值