【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;
    }
}
相关推荐
H Journey几秒前
Linux su 命令核心用法总结
java·linux·服务器·su
小学仔22 分钟前
科大镜像科大镜像科大镜像
java
小旭952723 分钟前
Java 反射详解
java·开发语言·jvm·面试·intellij-idea
HalvmånEver26 分钟前
Linux:线程创建与终止上(线程五)
java·linux·jvm
有来技术32 分钟前
ASP.NET Core 权限管理系统(RBAC)设计与实现|vue3-element-admin .NET 后端
vue.js·后端·c#·asp.net·.net
m0_7482331732 分钟前
PHP版本演进:从7.x到8.x全解析
java·开发语言·php
qq_124987075333 分钟前
基于springboot的林业资源管理系统设计与实现(源码+论文+部署+安装)
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
当战神遇到编程40 分钟前
图书管理系统
java·开发语言·单例模式
indexsunny41 分钟前
互联网大厂Java求职面试实战:Spring Boot微服务与Kafka消息队列应用解析
java·数据库·spring boot·微服务·面试·kafka·jpa
shuair1 小时前
springboot整合redisson单机模式
java·spring boot·后端