Field injection is not recommended

文章目录

  • [1. 引言](#1. 引言)
  • [2. 不推荐使用@Autowired的原因](#2. 不推荐使用@Autowired的原因)
  • [3. Spring提供了三种主要的依赖注入方式](#3. Spring提供了三种主要的依赖注入方式)
    • [3.1. 构造函数注入(Constructor Injection)](#3.1. 构造函数注入(Constructor Injection))
    • [3.2. Setter方法注入(Setter Injection)](#3.2. Setter方法注入(Setter Injection))
    • [3.3. 字段注入(Field Injection)](#3.3. 字段注入(Field Injection))
  • [4. 推荐方案](#4. 推荐方案)
  • [5. 参考博客](#5. 参考博客)

1. 引言

复制代码
Field injection is not recommended

意思就是不推荐使用字段注入的方式,不是不推荐@Autowired注解,以前为了简便就直接使用
@Resource代替,程序员都在不断追求完美。。。 接下来我们实实在在的分析一下为啥不推荐,以及到底推荐那种方式注入。

2. 不推荐使用@Autowired的原因

不推荐使用@Autowired进行字段注入的原因有以下几点:

  1. 紧耦合性(Tight Coupling):字段注入将依赖关系直接注入到类的字段上,导致类与依赖之间产生紧密的耦合。这使得代码难以修改和扩展,并且增加了对具体实现的依赖性。

  2. 隐藏依赖关系(Hidden Dependencies):字段注入隐藏了类的依赖关系,使代码不够透明和可读。读取代码时无法立即知道类所依赖的其他组件或服务。

  3. 单元测试困难(Difficult Unit Testing):由于字段注入需要依赖容器来自动注入依赖项,导致在编写单元测试时必须依赖完整的容器环境。这增加了测试的复杂性,并且可能会导致测试变慢或不稳定。

  4. 难以发现依赖问题(Dependency Issues):字段注入使得依赖可以在运行时更改,这增加了代码维护的复杂性。同时,如果依赖项没有正确配置或不存在,就会在运行时出现错误,而不是在编译时就能发现。

相比之下,构造器注入(Constructor Injection)或Setter方法注入(Setter Injection)提供了更好的可测试性、可维护性和代码清晰度。它们明确列出了类所需的依赖项,并使得依赖关系更加透明和易于理解。这些方法也更容易进行单元测试,且不需要依赖完整的容器环境。

3. Spring提供了三种主要的依赖注入方式

3.1. 构造函数注入(Constructor Injection)

通过构造函数将依赖项传递给目标类。这种方式明确声明了类所需的依赖项,并且使得类的实例在创建时就具备了必要的依赖关系。示例代码如下:

java 复制代码
@Component
public class SLFBClient {


    private final DataSourceFactory dataSourceFactory;

    /**
     * @Autowired 从spring4.3开始可以省略
     */
//    @Autowired
    public SLFBClient(DataSourceFactory dataSourceFactory) {
        this.dataSourceFactory = dataSourceFactory;
    }

}

3.2. Setter方法注入(Setter Injection)

通过Setter方法设置依赖项。这种方式允许使用默认构造函数创建类的实例,然后通过Setter方法来动态设置依赖项。示例代码如下:

java 复制代码
@Component
public class SLFBClient {


    private  DataSourceFactory dataSourceFactory;

    /**
     * @Autowired 从spring4.3开始可以省略
     */
//    @Autowired
    public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
        this.dataSourceFactory = dataSourceFactory;
    }
}

3.3. 字段注入(Field Injection)

通过直接将依赖项注入到类的字段上。这种方式最简洁,但也最不推荐使用(在之前的回答中已经详细解释了原因)。示例代码如下:

java 复制代码
@Component
public class SLFBClient {


//    @Autowired
//    @Resource
    @Inject
    private DataSourceFactory dataSourceFactory;


}

@Autowired、@Resource和@Inject是用于依赖注入的常见注解,它们在使用方式和一些细节上有一些区别。

  1. @Autowired:

    • 来自Spring框架。
    • 默认按照类型(byType)进行依赖注入,会尝试将匹配的bean自动注入到目标字段、构造函数或方法参数中。
    • 可以与@Qualifier一起使用,通过指定bean的名称或限定符来进一步指定要注入的bean。
    • @Autowired是非强制性的,可以在某些情况下将依赖项标记为可选。
  2. @Resource:

    • Java EE的标准注解,也可以被Spring框架支持。
    • 默认按照名称(byName)进行依赖注入,通过指定bean的名称来解析并注入匹配的bean
    • 可以使用name属性指定要注入的bean的名称。
    • @Resource是强制性的,要求找到匹配的bean进行注入,否则会抛出异常。
  3. @Inject:

    • Java CDI(Contexts and Dependency Injection)规范的一部分,可以由Java EE和一些其他框架(如Spring)支持。
    • 默认按照类型(byType)进行依赖注入,使用与@Autowired类似的机制。
    • 不支持required属性,即所有注入都被视为必需的。
    • 可以与@Qualifier一起使用,通过指定bean的名称或限定符来进一步指定要注入的bean

总结:

  • @AutowiredSpring特有的注解,默认按类型进行依赖注入。
  • @ResourceJava EE的标准注解,可被Spring支持,默认按名称进行依赖注入。
  • @InjectJava CDI规范的注解,也可被Spring等框架支持,默认按类型进行依赖注入。
  • 三个注解都可以与@Qualifier一起使用来指定具体要注入的bean
  • @Autowired@Inject在功能上相似,而@Resource功能稍有不同,但它们通常可以互相替代使用。

需要注意的是,具体在Spring中使用哪个注解,可以根据项目的需求、框架的支持以及个人偏好来决定。

4. 推荐方案

使用构造器注入的好处:

  • 保证依赖不可变(final关键字)
  • 保证依赖不为空(省去了我们对其检查)
  • 保证返回客户端(调用)的代码的时候是完全初始化的状态
  • 避免了循环依赖
  • 提升了代码的可复用性

推荐使用Lombok中的@RequiredArgsConstructor注解

复制代码
@Component
@RequiredArgsConstructor
public class SLFBClient {

    private final DataSourceFactory dataSourceFactory;

}

接下来我们探讨一下Lombok@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsContructor三个注解

  1. @NoArgsConstructor:
    • 自动生成一个无参构造函数。
    • 适用于不需要传入参数的情况。
java 复制代码
import lombok.NoArgsConstructor;

@NoArgsConstructor
public class MyClass {
    // Fields and methods
}

2. @RequiredArgsConstructor:

  • 自动生成一个包含所有被标记为final和@NonNull的字段的构造函数。
  • 适用于只关注部分字段并确保这些字段非空的情况。
java 复制代码
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class MyClass {
    private final String name;
    @NonNull
    private final Integer age;
    // Other fields and methods
}
  1. @AllArgsConstructor:
    • 自动生成一个包含所有类字段的构造函数。
    • 适用于需要一次性传递所有字段值的情况。
java 复制代码
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class MyClass {
    private String name;
    private int age;
    // Other fields and methods
}

5. 参考博客

Field Dependency Injection Considered Harmful

Field injection is not recommended(Spring团队不推荐使用Field注入)

【Spring】浅谈spring为什么推荐使用构造器注入

相关推荐
凭君语未可2 天前
详解Maven的主要生命周期
java·log4j·maven
WIN赢3 天前
单元测试的编写
单元测试·log4j
zerohawk6 天前
【log4j】配置Slf4j
junit·单元测试·log4j
熬了夜的程序员9 天前
Go 语言封装邮件发送功能
开发语言·后端·golang·log4j
故事与他64510 天前
Apache中间件漏洞攻略
java·服务器·安全·网络安全·中间件·log4j·apache
江沉晚呤时12 天前
精益架构设计:深入理解与实践 C# 中的单一职责原则
java·jvm·算法·log4j·.netcore·net
为美好的生活献上中指13 天前
java每日精进 3.21 【SpringBoot规范2.0】
java·开发语言·spring boot·log4j·async·mail
-$_$-14 天前
【MyDB】5-索引管理之4-单元测试
单元测试·log4j
爱的叹息18 天前
java自带日志系统介绍(JUL)以及和Log4j 2、Logback、SLF4J不同日志工具的对比
java·log4j·logback
热心小张23 天前
Springboot单元测试
spring boot·单元测试·log4j