【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;
    }
}
相关推荐
亚历克斯神10 分钟前
智能搜索系统的升级复盘——从 Elasticsearch 到混合检索的检索质量提升
java·spring·微服务
再吃一根胡萝卜25 分钟前
用 Rust 写一个桌面悬浮图标:为什么它比 Python 更适合 AI 桌面工具?
后端
IT_陈寒1 小时前
Vue的computed属性把我坑惨了,原来我一直用错姿势
前端·人工智能·后端
金銀銅鐵1 小时前
[Java] 一个方法最多可以有多少个入参?
java·jvm
哭哭啼1 小时前
JAVA服务问题诊断
java·开发语言·jvm
evans在进步2 小时前
Spring Boot 核心机制详解:可执行 JAR、CORS、静态资源与配置绑定
spring boot·后端·jar
Sayuanni%32 小时前
SpringBoot 从注解到源码:核心知识点总结
java·spring boot·后端
坚定信念,勇往无前2 小时前
Maven 私有仓库-nexus
java
Minner-Scrapy2 小时前
Scrapy 2.17 源码解析:Scheduler 调度器与磁盘/内存双队列
java·爬虫·python·scrapy·网络爬虫·twisted
晚风醉蝶2 小时前
1-11-奇偶排序-OddEvenSort
java·数据结构·算法