【Spring】为什么不建议使用 @Autowired 字段注入却还可以使用 @Resource

前言

  • hello,大家好,我是 Lorin,大家使用 Spring 框架 @Autowired 注解字段注入时是不是经常遇到这个问题,今天我们来看看为什么?
csharp 复制代码
Field injection is not recommended

版本

  • JDK 8
  • spring-boot-starter-parent 2.5.4

回顾一下 Spring 注入的三种方式

字段注入

Java 复制代码
public class TestService {

    @Autowired
    private DependencyA dependencyA;

    @Autowired
    private DependencyB dependencyB;
}

方法注入

Java 复制代码
public class TestService {

    private DependencyA dependencyA;

    private DependencyB dependencyB;

    @Autowired
    public void setDependencyA(DependencyA dependencyA) {
        this.dependencyA = dependencyA;
    }

    @Autowired
    public void setDependencyB(DependencyB dependencyB) {
        this.dependencyB = dependencyB;
    }
}

构造器注入

Java 复制代码
public class TestService {

    private final DependencyA dependencyA;

    private final DependencyB dependencyB;

    // @Autowired 可以省略
    @Autowired
    public TestService(DependencyA dependencyA, DependencyB dependencyB) {
        this.dependencyA = dependencyA;
        this.dependencyB = dependencyB;
    }
}

为什么不推荐 @Autowired 字段注入

  • 从上面我们可以看到字段注入是最简单且无其它额外代码的方式,但同时也存在以下问题:

组件与特定 IOC 框架强耦合(最主要原因)

  • 组件与特定 IOC 框架强耦合,导致使用其它 IOC 容器框架时很难兼容。同时也导致单元测试必须使用特定框架实现组件管理,不容易进行单元测试。

无法实现像构造器注入不可变对象

使用字段注入的依赖对外部不可见

容易使对象违反单一职责原则

  • 由于字段注入使用过于简单,容易使对象过分膨胀,违反单一职责原则。

@Autowired VS @Resource

  • @Autowired 是Spring定义的,而 @Resource 是JSR-250定义。
  • 依赖识别方式:@Autowired默认是byType,可以使用@Qualifier指定Name,@Resource默认使用ByName,如果找不到则使用ByType。
  • 适用对象:@Autowired可以对构造器、方法、字段使用,@Resource只能对方法、字段使用。

@Resource 为什么没有不推荐

  • 其实这是因为 @Autowired 是 Spring 提供的特定注解,和 Spring 框架绑定,而 @Resource 是JSR-250提供的,它是Java标准,作为 IOC 容器框架都是需要实现的,所以不存在上面的第一点问题。

一些最佳实践

  • 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. Note that use of the @Required annotation on a setter method can be used to make the property a required dependency.
  • 翻译: 我们可以使用混合使用构造器注入和方法注入,一个好的经验法则是对于强制依赖使用构造器注入,而非强制依赖使用方法注入。在方法注入上使用 @Required 将依赖标志为非必填。
Java 复制代码
public class TestService {

    /**
     * 必须依赖
     */
    private final DependencyA dependencyA;

    /**
     * 非必须依赖
     */
    private DependencyB dependencyB;

    public TestService(DependencyA dependencyA) {
        this.dependencyA = dependencyA;
    }

    @Autowired(required = false)
    public void setDependencyB(DependencyB dependencyB) {
        this.dependencyB = dependencyB;
    }

使用构造器注入带来的循环依赖问题

  • 如果我们使用构造器注入,那么可能会出现无法解析循环依赖的问题。这里提供两个解决方案:

使用方法注入(官网推荐)

  • One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.

使用 Lazy 注解(推荐但谨慎使用)

  • 一些场景下会导致初次请求处理变慢。
Java 复制代码
@Service
public class DependencyA {

    private final TestService testService;

    public DependencyA(@Lazy TestService testService) {
        this.testService = testService;
    }
}

@Service
public class TestService {

    private final DependencyA dependencyA;

    public TestService(DependencyA dependencyA) {
        this.dependencyA = dependencyA;
    }
}
相关推荐
2401_857610032 分钟前
Spring Boot框架:电商系统的技术优势
java·spring boot·后端
希忘auto18 分钟前
详解MySQL安装
java·mysql
冰淇淋烤布蕾30 分钟前
EasyExcel使用
java·开发语言·excel
拾荒的小海螺36 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
Jakarta EE1 小时前
正确使用primefaces的process和update
java·primefaces·jakarta ee
马剑威(威哥爱编程)1 小时前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
用户3157476081351 小时前
成为程序员的必经之路” Git “,你学会了吗?
面试·github·全栈
java—大象1 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_2 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端