【Spring】公司为什么禁止在SpringBoot项目中使用@Autowired注解

目录

前言

说明

依赖注入的类型

2.1 基于构造器的依赖注入

2.2 基于 Setter 的依赖注入

2.3 基于属性的依赖注入

基于字段的依赖注入缺陷

3.1 不允许声明不可变域

3.2 容易违反单一职责设计原则

3.3 与依赖注入容器紧密耦合

3.4 隐藏依赖关系

总结

参考文档


前言

Spring 官方已不推荐使用 Autowired 字段/属性注入 bean,一些大公司的新项目也明令禁止使用了。

说明

最近公司升级框架,由原来的 spring framework 3.0 升级到 5.0,然后写代码的时候突然发现 idea 在属性注入的 @Autowired 注解上给出警告提示,就像下面这样的,也是挺懵逼的,毕竟这么写也很多年了。

Field injection is not recommended

image.png

查阅了相关文档了解了一下,原来这个提示是 spring framework 4.0 以后开始出现的,spring 4.0 开始就不推荐使用属性注入,改为推荐构造器注入和 setter 注入。

下面将展示了 spring 框架可以使用的不同类型的依赖注入,以及每种依赖注入的适用情况。

依赖注入的类型

尽管针对 spring framework 5.1.3 的文档只定义了两种主要的依赖注入类型,但实际上有三种:

  • 基于构造器的依赖注入
  • 基于 setter 的依赖注入
  • 基于字段的依赖注入

其中基于字段的依赖注入被广泛使用,但是 idea 或者其他静态代码分析工具会给出提示信息,不推荐使用。

甚至可以在一些 Spring 官方指南中看到这种注入方法:

 

2.1 基于构造器的依赖注入

在基于构造函数的依赖注入中,类构造函数被标注为 @Autowired,并包含了许多与要注入的对象相关的参数。

 

 

@Component
public class ConstructorBasedInjection {private final InjectedBean injectedBean;@Autowired    public ConstructorBasedInjection(InjectedBean injectedBean) {        this.injectedBean = injectedBean;    }
}

然后在spring官方文档中,@Autowired 注解也是可以省去的。

 

 

public class SimpleMovieLister {// the SimpleMovieLister has a dependency on a MovieFinderprivate 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, 使得它们会在类实例化期间被初始化,这对于所需的依赖项很方便。

2.2 基于 Setter 的依赖注入

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

 

 

@Component
public class SetterBasedInjection {private InjectedBean injectedBean;@Autowiredpublic void setInjectedBean(InjectedBean injectedBean) {this.injectedBean = injectedBean;}
}

和基于构造器的依赖注入一样,在官方文档中,基于 Setter 的依赖注入中的 @Autowired 也可以省去。

 

 

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...
}

2.3 基于属性的依赖注入

在基于属性的依赖注入中,字段/属性被标注为 @Autowired。一旦类被实例化,Spring 容器将设置这些字段。

 

 

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

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

基于字段的依赖注入缺陷

3.1 不允许声明不可变域

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

3.2 容易违反单一职责设计原则

在面向对象的编程中,五大设计原则SOLID被广泛应用,(国内一般为六大设计原则),用以提高代码的重用性,可读性,可靠性和可维护性。

S 在 SOLID 中代表单一职责原则,即一个类应该只负责一项职责,这个类提供的所有服务都应该只为它负责的职责服务。

使用基于字段的依赖注入,高频使用的类随着时间的推移,我们会在类中逐渐添加越来越多的依赖项,我们用着很爽,很容易忽略类中的依赖已经太多了。但是如果使用基于构造函数的依赖注入,随着越来越多的依赖项被添加到类中,构造函数会变得越来越大,我们一眼就可以察觉到哪里不对劲。

有一个有超过10个参数的构造函数是一个明显的信号,表明类已经转变一个大而全的功能合集,需要将类分割成更小、更容易维护的块。

因此,尽管属性注入并不是破坏单一责任原则的直接原因,但它隐藏了信号,使我们很容易忽略这些信号。spring系列技术文章:Spring基础 - Spring 常用七大类注解 | 素文宅 (yoodb.com)

3.3 与依赖注入容器紧密耦合

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

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

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

3.4 隐藏依赖关系

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

总结

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

参考文档

Field injection is not recommended – Spring IOC by Marc Nuri

spring官方文档 1.4. Dependencies

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/681377.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络协议与攻击模拟_16HTTP协议

1、HTTP协议结构 2、在Windows server去搭建web扫描器 3、分析HTTP协议流量 一、HTTP协议 1、概念 HTTP(超文本传输协议)用于在万维网服务器上传输超文本(HTML)到本地浏览器的传输协议 基于TCP/IP(HTML文件、图片、查询结构等&…

数字IC实践项目(9)— Tang Nano 20K: I2C OLED Driver

Tang Nano 20K: I2C OLED Driver 写在前面的话硬件模块RTL电路和相关资源报告SSD1306 OLED 驱动芯片SSD1306 I2C协议接口OLED 驱动模块RTL综合实现 总结 写在前面的话 之前在逛淘宝的时候偶然发现了Tang Nano 20K,十分感慨国产FPGA替代方案的进步之快;被…

自动生成测试用例_接口测试用例自动生成工具

前言 写用例之前,我们应该熟悉API的详细信息。建议使用抓包工具Charles或AnyProxy进行抓包。 har2case 我们先来了解一下另一个项目har2case 他的工作原理就是将当前主流的抓包工具和浏览器都支持将抓取得到的数据包导出为标准通用的 HAR 格式(HTTP A…

【AI】安装ubuntu20.04教程(未完待续)

目录 1 制作ubuntu20.04系统盘1.1 下载ubuntu镜像1.2 使用ultraiso写入镜像 2 安装Ubuntu系统 1 制作ubuntu20.04系统盘 1.1 下载ubuntu镜像 在清华镜像站https://mirrors.tuna.tsinghua.edu.cn/下载ubuntu20.04镜像 路径为/ubuntu-releases/20.04/,下载ubuntu-20…

操作系统(16)----磁盘相关

目录 一.磁盘相关概念 1.磁盘 2.磁道 3.扇区 4.盘面、柱面 5.磁盘的分类 二.磁盘调度算法 1.一次磁盘读/写操作需要的时间 2.先来先服务算法(FCFS) 3.最短寻找时间优先(SSTF) 4.扫描算法(SCAN) 5.LOOK调度算法 6.循环扫描算法(C-SCAN) 7.C-LOOK调度算法 三.减少…

9.【CPP】List (迭代器的模拟实现||list迭代器失效||list的模拟实现)

介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。list与forward_…

CSDN文章导出PDF整理状况一览

最近CSDN有了导出文章PDF功能,导出的PDF还可以查询, 因此,把文章导出PDF,备份一下自己的重要资料。 目前整理内容如下 No.文章标题整理时间整理之后 文章更新Size (M)10001_本地电脑-开发相关软件保持位…

华为机考入门python3--(12)牛客12-字符串反转

分类:字符串 知识点: 字符串是否为空 if not my_str 字符串逆序 my_str[::-1] 题目来自【牛客】 def reverse_string(s): # 判断字符串是否为空或只包含空格 if not s.strip(): return "" # 使用Python的切片语法反转字符串 re…

Pytorch的可视化

1 使用 wandb进行可视化训练过程 本文章将从wandb的安装、wandb的使用、demo的演示进行讲解。 1.1 如何安装wandb? wandb的安装比较简单,在终端中执行如下的命令即可: pip install wandb在安装完成之后,我们需要,去…

matlab入门,在线编辑,无需安装matab

matlab相关教程做的很完善,除了B站看看教程,官方教程我觉得更加高效。跟着教程一步一步编辑,非常方便。 阅读 MATLAB 官方教程: MATLAB 官方教程提供了从基础到高级的教学内容,内容包括 MATLAB 的基本语法、数据处理…

【JavaScript】Promise 和异步操作

文章目录 1. 什么是Promise2. 基本用法使用.then()处理成功状态使用.catch()处理失败状态链式调用 3. Promise.all() 和 Promise.race()Promise.all()Promise.race() 4. 异步操作与async/await使用 async/await 5. 总结 在 JavaScript 中, Promise 是一种处理异步操…

Vue3高频知识点和写法

一 Vue插件 二 vue3项目创建 创建完成后npm install npm run dev 三 setup 一 响应式数据 setup函数是用来代替data和methods的写法的,在setup函数中声明的数据和函数,导出后可以在页面中使用。 但是暂时不是响应式数据,如果要响应式数据的…

C++笔记1:操纵符输入输出

C操纵符用来控制输出控制,一是输出的形式,二是控制补白的数量和位置。本文记录一下,在一些笔试的ACM模式可能有用。其中1-4节的部分是关于格式化输入输出操作,5-6节的部分是关于未格式化输入输出操作。 1. 控制布尔值的格式 一般…

C语言—基础数据类型(含进制转换)

进制转换不多,但我觉得适合小白(我爱夸自己嘿嘿) 练习 1. 确认基础类型所占用的内存空间(提示:使用sizeof 运算符): 在这里我说一下,long 类型通常占用 4 字节。在 64 位系统上,long 类型通常也可为 8 字节。 格式…

LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】

文章目录 前言LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】题目链接与分类思路 资料获取 前言 博主介绍:✌目前全网粉丝2W,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领…

【ASP.NET Core 基础知识】--测试--单元测试和集成测试

一、单元测试 1.1 单元测试概述 单元测试是软件开发中的一种测试方法,用于验证软件中的最小可测试单元——通常是函数、方法或类——的行为是否符合预期。它的核心思想是将程序分解成独立的单元,并针对每个单元编写测试用例,以验证其功能是…

假期day9(2024/2/14)

获取数据库查询的值并调用值使用函数:sqlite3_get_table 在回调函数中获取数据库查询值,无法在其他函数调用:使用函数sqlite3_exec(db, sql, select_callback, &flag, &errmsg) 创建表 create table if not exists 表名…

力扣代码学习日记一

Problem: 389. 找不同 文章目录 思路解题方法复杂度Code 思路 给定两个字符串 s 和 t ,它们只包含小写字母。 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。 示例 1: 输入:s "a…

c++ 自定义Logger 日志类

Logger 日志类 线程安全的日志组件 默认保存到文件&#xff0c;并支持回调函数&#xff0c;比如显示到界面 #ifndef LOGGER_H #define LOGGER_H#include <iostream> #include <sstream> #include <mutex> #include <thread> #include <iomanip&g…

低资源学习与知识图谱:构建与应用

目录 前言1 低资源学习方法1.1 数据增强1.2 特征增强1.3 模型增强 2 低资源知识图谱构建与推理2.1 元关系学习2.2 对抗学习2.3 零样本关系抽取2.4 零样本学习与迁移学习2.5 零样本学习与辅助信息 3 基于知识图谱的低资源学习应用3.1 零样本图像分类3.2 知识增强的零样本学习3.3…