【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;
    }
}
相关推荐
钢门狂鸭2 小时前
关于rust的crates.io
开发语言·后端·rust
Lionel_SSL3 小时前
《深入理解Java虚拟机》第三章读书笔记:垃圾回收机制与内存管理
java·开发语言·jvm
记得开心一点嘛3 小时前
手搓Springboot
java·spring boot·spring
老华带你飞3 小时前
租房平台|租房管理平台小程序系统|基于java的租房系统 设计与实现(源码+数据库+文档)
java·数据库·小程序·vue·论文·毕设·租房系统管理平台
独行soc3 小时前
2025年渗透测试面试题总结-66(题目+回答)
java·网络·python·安全·web安全·adb·渗透测试
脑子慢且灵4 小时前
[JavaWeb]模拟一个简易的Tomcat服务(Servlet注解)
java·后端·servlet·tomcat·intellij-idea·web
华仔啊5 小时前
SpringBoot 中 6 种数据脱敏方案,第 5 种太强了,支持深度递归!
java·后端
异常驯兽师6 小时前
Spring 中处理 HTTP 请求参数注解全解析
java·spring·http
连合机器人6 小时前
晨曦中的守望者:当科技为景区赋予温度
java·前端·科技
AD钙奶-lalala6 小时前
idea新建的项目new 没有java class选项
java·ide·intellij-idea