【笔记】浅析Field injection is not recommended

news/2024/10/26 17:10:10/

IDEA运行SpringBoot项目,遇到以下有关 @Autowired 注解的警告:Field injection is not recommended . 这篇文章浅析这个问题,为什么会有这样的提示?为什么字段注入的方式不推荐?

当前的 spring framework (5.0.3) 文档仅定义了两种主要的注入类型1

DI exists in two major variants: Constructor-based dependency injection and Setter-based dependency injection.

基于构造函数的依赖注入:在基于构造函数的依赖注入中,类构造函数被注释@Autowired并包含可变数量的参数以及要注入的对象。

public class SimpleMovieLister {// the SimpleMovieLister has a dependency on a MovieFinderprivate final MovieFinder movieFinder;// a constructor so that the Spring container can inject a MovieFinderpublic SimpleMovieLister(MovieFinder movieFinder) {this.movieFinder = movieFinder;}// business logic that actually uses the injected MovieFinder is omitted...
}

基于构造函数的注入的主要优点是您可以将注入的字段声明为final,因为它们将在类实例化期间启动。这对于所需的依赖项很方便。

基于Setter的依赖注入:在基于 setter 的依赖注入中,setter 方法用@Autowired. 一旦使用无参数构造函数或无参数静态工厂方法实例化 Bean,Spring 容器将调用这些 setter 方法以注入 Bean 的依赖项。

public class SimpleMovieLister {// the SimpleMovieLister has a dependency on the MovieFinderprivate MovieFinder movieFinder;// a setter method so that the Spring container can inject a MovieFinderpublic void setMovieFinder(MovieFinder movieFinder) {this.movieFinder = movieFinder;}// business logic that actually uses the injected MovieFinder is omitted...
}

但实际上还有第三种,也是被广泛应用的

基于字段的依赖注入:在基于字段的依赖注入中,字段/属性用@Autowired. 实例化类后,Spring 容器将设置这些字段。

@Component
public class ConstructorBasedInjection {@Autowiredprivate InjectedBean injectedBean;}

这是注入依赖项的最简洁的方法,因为它避免了添加样板代码,并且无需为类声明构造函数。代码看起来不错,简洁明了,但正如代码检查员已经提示我们的那样,这种方法有一些缺点。

那么为什么不推荐使用基于字段的依赖注入?

基于字段的依赖注入缺点2

不允许不可变字段声明

基于字段的依赖注入不适用于声明为 final/immutable 的字段,因为这些字段必须在类实例化时实例化。声明不可变依赖项的唯一方法是使用基于构造函数的依赖项注入。

违反了单一责任原则

如您所知,在面向对象的计算机编程中,SOLID3首字母缩略词定义了五个设计原则,这些原则将使您的代码易于理解、灵活和可维护。SOLID中的S代表单一职责原则,这意味着一个类应该只负责软件应用程序功能的单个部分,并且它的所有服务都应该与该职责严格对齐。

使用基于字段的依赖注入,很容易在你的类中有很多依赖,一切看起来都很好。如果改为使用基于构造函数的依赖注入,随着更多的依赖项被添加到你的类中,构造函数变得越来越大。拥有一个包含十个以上参数的构造函数是一个明显的标志,表明该类有太多协作者,这可能是开始将类拆分为更小且更易于维护的部分的好时机。

这里要说明:基于构造函数依赖注入,并不说能够解决类里面的过多依赖的问题。而是说能够直观的提示我们:这个类被注入了太多的依赖,你该停下来,优化并拆分你的业务逻辑了!

因此,尽管字段注入并不直接导致打破单一责任原则,但它肯定有助于隐藏信号,否则这些信号会非常明显。

与依赖注入容器紧密耦合

使用基于字段的注入的主要原因是避免getter和setter的样板代码或为您的类创建构造函数。最后,这意味着可以设置这些字段的唯一方法是通过Spring容器实例化类并使用反射注入它们,否则字段将保持为 null 并且您的类将被破坏/无用。

依赖注入设计模式将类依赖的创建与类本身分开,将此责任转移到类注入器,允许程序设计松散耦合并遵循单一职责和依赖倒置原则(再次是SOLID)。因此,最终通过自动装配其字段实现的类解耦会因再次与类注入器(在本例中为 Spring)耦合而丢失,从而使该类在 Spring 容器之外无用。

这意味着如果你想在应用程序容器之外使用你的类,例如用于单元测试,你必须使用 Spring 容器来实例化你的类,因为没有其他可能的方法(除了反射)来设置自动装配的字段。

隐藏的依赖

使用依赖注入模式时,受影响的类应该使用公共接口清楚地公开这些依赖关系,方法是在构造函数中公开所需的依赖关系,或者使用方法(setter)公开可选的依赖关系。当使用基于字段的依赖注入时,该类本质上将这些依赖隐藏到外部世界。

结论

我们已经看到应该尽可能避免基于字段的注入,因为它有许多缺点,无论它看起来多么优雅。推荐的方法是使用基于构造函数和基于设置器的依赖注入。对于必需的依赖项,建议使用基于构造函数的注入,以允许它们不可变并防止它们为空。对于可选的依赖项,建议使用基于 Setter 的注入。


  1. 《Spring Framework Documentation 1.4.1. Dependency Injection》 https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-collaborators ↩︎

  2. 《Field injection is not recommended – Spring IOC》 https://blog.marcnuri.com/field-injection-is-not-recommended#eases-single-responsibility-principle-violation ↩︎

  3. 《Wiki SOLID》 https://en.wikipedia.org/wiki/SOLID ↩︎


http://www.ppmy.cn/news/27337.html

相关文章

2022年全国职业院校技能大赛(中职组)网络安全竞赛试题A模块(4)

目录 二、竞赛注意事项 (本模块20分) 一、项目和任务描述: 二、服务器环境说明 三、具体任务(每个任务得分以电子答题卡为准) A-1任务一 登录安全加固(Windows) 1.密码策略 a.更改或创建…

Open3D 点云高程归一化(基于2维地面点,Python版本)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 之前的博客中Open3D 点云高程归一化(基于地面点,Python版本)是基于三维空间进行最近地面点的查询操作,这里对其进行修改一下,将点云投影到水平面,基于二维空间进行最近地面点的查询,这种方式对一些较为陡峭的…

STM32f103 CubeMX封装 led程序

本文代码使用 HAL 库。 文章目录前言一、LED 原理图二、CubeMX创建工程三、LED 相关函数1. 输出电平函数:2. 延时函数:3. 翻转电平函数:四、详细代码实验现象 :总结代码 源码:前言 从这篇文章开始,我们讲解…

Java缓存面试题——Redis应用

文章目录1、为什么要使用Redis做缓存?2、为什么Redis单线程模型效率也能那么高?3、Redis6.0为什么要引入多线程呢?4、Redis常见数据结构以及使用场景字符串(String)哈希(Hash)列表(list)集合&am…

机器学习主要内容的思维导图

机器学习 机器学习: 定义:能够从经验中学习从而能够 把事情不断做好的计算机程序 人工智能的一个分支和 实现方式 理论基础:概率论 数理统计 线性代数 数学分析 数值逼近 最优化理论 计算复杂理论 核心要素:数据 算法 模型 机器…

[数据结构]时间复杂度与空间复杂度

[数据结构]时间复杂度与空间复杂度 如何衡量一个算法的好坏 long long Fib(int N) {if(N < 3)return 1;return Fib(N-1) Fib(N-2); } 这是一个求斐波那契数列的函数&#xff0c;使用递归的方法求得&#xff0c;虽然代码看起来很简洁&#xff0c;但是简洁真的就好吗&#…

华为OD机试真题Python实现【 喊七】真题+解题思路+代码(20222023)

喊七 题目 喊 7,是一个传统的聚会游戏, N 个人围成一圈,按顺时针从1 - 7编号, 编号为1的人从1开始喊数, 下一个人喊得数字是上一个人喊得数字+1, 但是当将要喊出数字7的倍数或者含有7的话, 不能喊出,而是要喊过。 假定N个人都没有失误。 当喊道数字k时, 可以统计每…

OSCP-课外1(http万能密码、hydra密码暴力破解http、代码审计、Win缓存区溢出)

目录 难度 主机发现&端口扫描 信息收集 万能密码 hydra密码暴力破解