阿里二面:谈谈 @Autowired 和 @Resource 两个注解的区别

这两个注解都是用来实现依赖注入的。

在 Spring 框架中,依赖注入(DI)是实现控制反转(IoC)的核心机制之一。通过 DI,对象无需自行创建或查找其依赖项,而是由外部容器负责注入。而目前实现依赖注入的两种主流方案便是使用 @Autowired 和 @Resource 注解。

依赖注入本质解决了什么问题?

依赖注入的本质是解决对象之间的直接依赖关系(耦合关系)问题,一个对象中需要使用其它对象时,通常会通过 new 关键字来显式创建出相关对象,这样的操作会导致各个对象之间高度耦合、对象难以复用等问题。而依赖注入是一种反向控制的思想,即对象不再直接操作其他对象,而是通过容器(例如 Spring)来进行依赖注入,容器在运行时动态地给对象注入其所需要的依赖关系,从而降低了对象之间的耦合度,并提高了对象的复用性。

理解了依赖注入,接下来进入正题,分析下 @Autowired 和 @Resource 注解注入机制的区别。

出身背景不同

  • @Autowired:Spring 原生注解,位于 org.springframework.beans.factory.annotation 包,其使用依赖于 Spring 框架。
  • @Resource:Java 标准注解(JSR-250 规范定义),位于 javax.annotation 包,可跨容器移植。

JSR 是 Java Specification Requests 的缩写,指的是由 JCP(Java Community Process)管理的一系列规范提议,旨在扩展和改进 Java 平台的功能。提议可由不同的组织或个人提出,这些提议提交通过后就会以 JSR-XXX 的方式发布,比如上述提到的 JSR-250 规范,就是定义了一系列通用注解 @PostConstruct@PreDestroy, 和 @Resource 等,用于简化应用程序的开发。

为什么使用 @Resource 注解可跨容器移植?因为 @Resource 是 Java 官方标准注解,在任何支持 JSR-250 标准的地方都可以使用。比如我们现在的项目从 Spring 换到了其它的框架,使用 @Resource 可保证正常的依赖注入,而使用 @Autowired 的话,因为它是专属于 Spring 框架的,可能就会编译报错了。

注入策略不同

注入查找策略有两种:按名称(byName)查找或按类型(byType)查找。

  1. @Autowired 注解默认是按照类型(byType)来查找装配依赖对象的,如果按照类型匹配到了多个 bean,则按照字段名称(byName)作为 bean 的名字去查找。如下:
// 优先按照 DatabaseService.class 类型查找,查找到多个就按照 'mysqlServiceImpl' 名称进行匹配
@Autowired
private DatabaseService mysqlServiceImpl;

如果查找到最终也找不到唯一匹配的 bean,则会抛出异常。为了避免异常情况,Spring 提供了以下措施:

  • 设置 required=false:当设置 required=false 时,即使没有找到匹配的 bean,也不会抛出异常,而是将该依赖设为 null
@Autowired(required = false)
private DatabaseService databaseService;
  • 结合 @Qualifier 使用:当存在多个相同类型的 bean 时,可以通过 @Qualifier 注解指定具体的 bean 名称来进行精确注入。
@Autowired
@Qualifier("mysqlServiceImpl")
private DatabaseService databaseService;
  1. @Resource 注解默认是按照名称(byName)来查找装配依赖对象的。@Resource 有两个重要的属性:name 和 type,而 Spring 将 @Resource 注解的 name 属性解析为 bean 的名字,而 type 属性则解析为 bean 的类型。
  • 按名称注入(默认):如果没有指定 name 属性,Spring 将尝试使用该成员变量的字段名作为 bean 的名字进行查找。例如,下边示例代码中字段名为 databaseService,Spring 会尝试查找名称为 databaseService 的 bean。如果按名称未能找到匹配的 bean,Spring 接下来会尝试基于类型(byType)来匹配。如果此时发现多个相同类型的 bean,则会抛出 NoUniqueBeanDefinitionException 异常,因为无法确定应选择哪个 bean 进行注入。
// 会优先尝试查找名为 'databaseService' 的 bean,找不到则按照 DatabaseService.class 类型再去查找
@Resource
private DatabaseService databaseService;
  • 指定了 name 属性:Spring 会严格按照给定的名称查找对应的 bean 进行注入。
// 查找容器中名称为 'mysqlServiceImpl' 的 bean 进行注入
@Resource(name = "mysqlServiceImpl")
private DatabaseService databaseService;
  • 指定了 type 属性:这种模式下,Spring 将忽略名称,而仅基于类型进行匹配。如果容器中存在多个相同类型的 bean,则会抛出异常。这时,我们要么确保只有一个符合条件的 bean,要么结合使用 name 属性来明确指定需要的 bean 名称。
// 按类型查找,需要确保能找到唯一的 bean,否则会抛出异常
@Resource(type = DatabaseService.class)
private DatabaseService databaseService
;

注入支持不同

  1. @Autowired 支持如下 3 种方式:
  • 属性注入:直接在类的字段上使用 @Autowired 注解即可完成依赖注入。
public class BizService {
    @Autowired
    private DatabaseService databaseService;
}
  • 构造方法注入:通过在构造函数上使用 @Autowired 注解来依赖注入,这也是 Spring 团队推荐的方式。
public class BizService {
    private final DatabaseService databaseService;

    @Autowired
    public MyComponent(DatabaseService databaseService) {
        this.databaseService = databaseService;
    }
}

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies.

意思是:对于强制性依赖关系就用构造函数方式注入,对于可选依赖就用 setter 方式注入。

  • Setter 方法注入:通过在 setter 方法上使用 @Autowired 注解来依赖注入。
public class BizService {
    private DatabaseService databaseService;

    @Autowired
    public void setDatabaseService(DatabaseService databaseService) {
        this.databaseService = databaseService;
    }
}
  1. @Resource 注解只支持属性注入和 Setter 方法注入,使用 @Resource 注解进行构造方法注入时 IDE 就会提示以下错误:
阿里二面:谈谈 @Autowired 和 @Resource 两个注解的区别

总结

  • 出身背景不同@Autowired 是 Spring 框架的,而 @Resource 是 Java 的,是 JSR-250 规范中提供的;
  • 注入策略不同@Autowired 注解先根据类型(byType)查找,如果存在多个 bean 再根据名称(byName)进行查找;而 @Resource 注解是先根据名称(byName)查找,如果查找不到,再根据类型(byType)进行查找;
  • 注入支持不同@Autowired 注解支持属性注入、构造方法注入和 Setter 注入,而 @Resource 注解只支持属性注入和 Setter 注入。

您的鼓励对我持续创作非常关键,如果本文对您有帮助,请记得点赞、分享、在看哦~~~谢谢!


原文始发于微信公众号(Java驿站):阿里二面:谈谈 @Autowired 和 @Resource 两个注解的区别

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/312818.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!