当前位置: 首页 > news >正文

深度剖析:为什么 Spring 和 IDEA 都不推荐使用 @Autowired 注解

目录

  1. 依赖注入简介

  2. @Autowired 注解的优缺点

  3. Spring 和 IDEA 不推荐使用 @Autowired 的原因

    • 构造器注入的优势

    • @Autowired 注解的局限性

    • 可读性和可测试性的问题

  4. 推荐的替代方案

    • 构造器注入

    • Setter 注入

    • Java Config @Bean 注解

  5. 项目示例:@Autowired vs 构造器注入

    • 示例代码

    • 可读性和可测试性的对比

  6. 总结

1. 依赖注入简介

依赖注入是一种设计模式,用于实现对象之间的解耦。在传统的编程方式中,一个类通常会直接创建它所依赖的对象,这导致了高度的耦合性和难以进行单元测试。而依赖注入则是通过外部化组件的创建和管理来实现对象间的松耦合。

Spring 框架使用了依赖注入这一设计模式,使得对象的创建和管理更加灵活。例如,下面是一个简单的依赖关系示例:


public class Service {private Repository repository;// 传统的依赖方式public Service() {this.repository = new Repository();}}

在上述代码中,Service 类直接创建了一个 Repository 对象,导致两者之间存在紧密的耦合。而使用依赖注入后,可以改写为:


public class Service {private Repository repository;// 依赖注入public Service(Repository repository) {this.repository = repository;}}

这样,Service 类的依赖通过构造器注入的方式被外部传入,从而实现了解耦。

2. @Autowired 注解的优缺点

在 Spring 框架中,@Autowired 注解用于自动注释框架中所需的依赖。许多开发者在使用 Spring 时,会利用 @Autowired 注解,将其直接应用于类的字段、构造器或 Setter 方法中,以实现自动注入。


@Componentpublic class Service {@Autowiredprivate Repository repository;}

优点

  1. 易于使用:通过简单地添加 @Autowired 注解,即可实现依赖注入,减少了手工编写代码的复杂性。

  2. 减少样板代码:@Autowired 注解减少了代码中显示注入所需要的样板代码。

  3. 自动扫描和装配:Spring 会自动扫描应用程序上下文中的所有 Bean,并进行自动装配,提供了快速开发的便利性。

缺点

  1. 难以测试:字段注入不便于进行单元测试,特别是在没有 DI 容器(如 Spring Context)的情况下。

  2. 隐式依赖:@Autowired 注解的使用有时会造成依赖关系的不明显,使代码的读者难以理解对象的依赖结构。

  3. 不推荐的实践:Spring 官方以及主流开发工具(例如 IntelliJ IDEA)已经不推荐直接使用字段注入。

3. Spring 和 IDEA 不推荐使用 @Autowired 的原因

构造器注入的优势

  1. 强制依赖变量初始化:通过构造函数注入,类在实例化时必须注入所有依赖,确保了依赖变量在类实例化时就能够被正确初始化。

  2. 不变性:构造函数注入提倡依赖变量的不变性(final),这样可以确保引用一旦被注入,便不会被更改,从而提高了代码的安全性和可维护性。

  3. 简化测试:通过构造函数注入,可以方便地进行单元测试而无需启动整个 Spring 容器,只需传递模拟对象(Mock objects)即可。

@Autowired 注解的局限性

  1. 反射开销:使用 @Autowired 注解时,Spring 容器在运行时需要使用反射机制来注入依赖,这带来了额外的性能开销。

  2. 隐式依赖关系:当使用字段注入时,依赖关系变得隐式,这会导致代码的可读性下降,需要更多文档和注释解释类的依赖关系。

  3. 代码可维护性差:当类的依赖越来越多时,使用 @Autowired 注解会使代码变得复杂,增加了维护的难度。

可读性和可测试性的问题

  1. 代码可读性差:@Autowired 注解使外部依赖的绑定显得不够直观,开发者在阅读代码时需要额外的心智负担来追踪依赖关系。

  2. 增加测试复杂性:使用字段注入会使单元测试变得困难,因为需要在测试中启动 Spring 容器或使用反射来初始化依赖对象。

  3. 脆弱性:如果依赖对象未正确注入,@Autowired 注解的字段会处于不确定状态,这可能会在运行时导致 NullPointerException。

4. 推荐的替代方案

虽然 @Autowired 注解提供了快速实现依赖注入的方式,但从长期的维护性和可测试性考虑,有更为推荐的替代方案:

构造器注入

构造器注入是一种显式的依赖注入方式,可以确保依赖对象在类实例化时被正确注入。这是一种更安全、可测试性更高的注入方式。


@Componentpublic class Service {private final Repository repository;@Autowiredpublic Service(Repository repository) {this.repository = repository;}}

Setter 注入

Setter 注入是一种通过 Setter 方法设置依赖的方式。虽然使用频率相对较低,但在某些需要可选依赖的情况下,Setter 注入是一种灵活的选择。


@Componentpublic class Service {private Repository repository;@Autowiredpublic void setRepository(Repository repository) {this.repository = repository;}}

Java Config @Bean 注解

使用 Java 配置类和 @Bean 注解,可以显式地定义和注入 Bean,从而实现更灵活的依赖注入。


@Configurationpublic class AppConfig {@Beanpublic Repository repository() {return new Repository();}@Beanpublic Service service() {return new Service(repository());}}

5. 项目示例:@Autowired vs 构造器注入

通过一个简单的项目示例,我们可以更直观地理解 @Autowired 和构造器注入之间的区别。

示例代码

使用 @Autowired 注解

@Componentpublic class Service {@Autowiredprivate Repository repository;public void performService() {repository.doSomething();}}@Componentpublic class Repository {public void doSomething() {// 执行数据库操作}}
使用构造器注入

@Componentpublic class Service {private final Repository repository;@Autowiredpublic Service(Repository repository) {this.repository = repository;}public void performService() {repository.doSomething();}}@Componentpublic class Repository {public void doSomething() {// 执行数据库操作}}

可读性和可测试性的对比

可读性

使用构造器注入时,依赖关系显而易见,读者一眼就可以看到该类需要的所有依赖。这使得代码的理解和管理变得更加容易,而不需要额外的注释来解释注入的依赖。

可测试性

使用构造器注入时,可以轻松地进行单元测试,无需启动整个 Spring 容器,只需传递模拟对象即可:


public class ServiceTest {@Testpublic void testPerformService() {Repository mockRepository = mock(Repository.class);Service service = new Service(mockRepository);// 测试业务逻辑service.performService();// 验证方法调用verify(mockRepository).doSomething();}}

而使用 @Autowired 注解时,进行单元测试则变得更为复杂,需要额外的代码启动 Spring 容器或使用反射机制:


@RunWith(SpringRunner.class)@SpringBootTestpublic class ServiceTest {@Autowiredprivate Service service;@MockBeanprivate Repository repository;@Testpublic void testPerformService() {// 测试业务逻辑service.performService();// 验证方法调用verify(repository).doSomething();}}

6. 总结

通过本文的详细分析,我们可以看出为什么 Spring 和 IntelliJ IDEA 都不推荐使用 @Autowired 注解。主要原因包括:

  1. 构造器注入的优势明显,不仅可以强制依赖变量初始化,还能提高代码的安全性和可维护性。

  2. @Autowired 注解的使用会导致代码的隐式依赖关系,降低代码的可读性和可维护性。

  3. 使用构造器注入或者其它显式的依赖注入方式,可以使代码更易于测试,避免了启动整个 Spring 容器的麻烦。

为了提高代码质量,增强代码的可读性和可测试性,开发者应尽量避免使用 @Autowired 注解,而优先选择构造器注入、Setter 注入或者 Java Config @Bean 注解等显式的依赖注入方式。通过这些替代方案,不仅可以提升代码的整体质量,还能在不同的开发阶段(如维护和测试)中,减少不必要的复杂性和潜在问题。希望本文的分析和建议能为广大开发者提供有价值的参考。

相关文章:

深度剖析:为什么 Spring 和 IDEA 都不推荐使用 @Autowired 注解

目录 依赖注入简介 Autowired 注解的优缺点 Spring 和 IDEA 不推荐使用 Autowired 的原因 构造器注入的优势 Autowired 注解的局限性 可读性和可测试性的问题 推荐的替代方案 构造器注入 Setter 注入 Java Config Bean 注解 项目示例:Autowired vs 构造器…...

【接口自动化_05课_Pytest接口自动化简单封装与Logging应用】

一、关键字驱动--设计框架的常用的思路 封装的作用:在编程中,封装一个方法(函数)主要有以下几个作用:1. **代码重用**:通过封装重复使用的代码到一个方法中,你可以在多个地方调用这个方法而不是…...

信息学奥赛初赛天天练-14-阅读程序-字符数组、唯一分解定理应用

更多资源请关注纽扣编程微信公众号 1 2019 CSP-J 阅读程序1 (程序输入不超过数组或字符串定义的范围;判断题正确填√,错误填;除特殊说明外,判断题1.5分,选择题3分,共计40分) 1 输入的字符串只能由小写字母或大写字母组…...

K210 数字识别 笔记

一、烧写固件 连接k210开发板,点开烧录固件工具,选中固件,并下载 二、模型训练 网站:MaixHub 1、上传文件 2、开始标记数据 添加9个标签,命名为1~9,按键盘w开始标记,键盘D可以下一张图片&…...

人脸检测--FaceNet(四)

FaceNet 是一个由 Google 研究团队开发的人脸识别系统,它基于深度学习技术,可以实现高精度的人脸识别、验证和聚类任务。FaceNet 通过学习直接从图像像素到人脸嵌入的映射,使得它在各种人脸识别任务中表现出色。下面是对 FaceNet 的详细介绍&…...

Android性能优化方案

1.启动优化: application中不要做大量耗时操作,如果必须的话,建议异步做耗时操作2.布局优化:使用合理的控件选择,少嵌套。(合理使用include,merge,viewStub等使用)3.apk优化(资源文件优化&#…...

视频监控平台AS-V1000 的场景管理,一键查看多画面视频的场景配置、调用、管理(一键浏览多路视频)

目录 一、场景管理的定义 二、场景管理的功能和特点 1、功能 (1)场景配置 (2)实时监控 (3)权限管理 2、特点 三、AS-V1000的场景配置和调用 1、场景配置 (1)实时视频预览 …...

微服务架构五大设计模式详解,助你领跑行业

微服务架构设计模式详解(5种主流模式) 微服务架构 微服务,一种革命性的架构模式,主张将大型应用分解为若干小服务,通过轻量级通信机制互联。每个服务专注特定业务,具备独立部署能力,轻松融入生产环境,为系…...

【problem】解决EasyExcel导出日期数据显示为#####问题

前言 在使用EasyExcel进行数据导出时,你可能遇到日期或其他数据在Excel中显示为“#######”的情况,这通常是因为列宽不足以展示单元格内的全部内容。本文将指导你如何通过简单的步骤解决这一问题,并确保导出的Excel文件自动调整列宽或直接指…...

Pytest用例自定义 - 重复、并行、串行

简介:面对快速迭代和持续交付的需求,提高测试效率变得至关重要。并行测试因其显著的时间节省优势而备受青睐。然而,并非所有测试都适合并行执行。在某些情况下,串行执行是必要的,以确保测试的正确性和稳定性。本文将探…...

前端项目上线

目录 1项目打包 2本地服务器部署 2.1具体操作步骤 2.2解决刷新 404 问题 2.3请求无法发送问题 3nginx 服务器部署 3.2nginx 配置代理练习 安装nginx nginx部署启动项目 3.3nginx 部署前端项目 4云服务器部署 本地资源上传 配置服务器与nginx 1项目打包 ●我…...

redis基本数据结构与应用

文章目录 概要String结构Hash结构List结构Set结构Zset结构bitmap位图类型geo地理位置类型其他常用命令 概要 redis常用的5种不同数据结构类型之间的映射如下: 结构类型结构存储的值结构的读写能力STRING可以是字符串、整数或者浮点数key-value形式;对整…...

Python pands使用引擎实现excel条件格式

截至我的知识更新日期(2023年),Pandas 库本身并不直接支持Excel条件格式。Pandas 是一个强大的Python数据分析库,它主要用于数据分析和操作,而不是用于创建或编辑Excel文件的格式。 然而,你可以使用 openp…...

基于 vuestic-ui 实战教程 - 登录篇

1. 简介 登录做为一个系统的门面,也是阻挡外界的一道防线,那在vuestic-ui中如何做登录功能呢。在这里就之间沿用初始版本的Login页面,作为一个演示模板,后续需要改进的读者可以在此篇文章的基础上修改。 2. 登录接口相关api 与 t…...

SAPUI5基础知识2 - 手动创建一个SAPUI5的项目

1. 前言 在本篇文章中,我们将手动一步一步建立出第一个SAPUI5的 ‘Hello World!’ 项目。 2. 步骤详解 2.1 在BAS中建立Dev Space 进入SAP Business Application Studio的Dev Space Manger,选择创建Dev Space。 勾选HTML5 Application Template插件…...

设计模式--访问者模式

访问者模式是一种行为设计模式,它用于将算法与对象结构分离,使得算法可以独立于使用它的数据结构而变化。这种模式在许多应用场景中非常有用,例如在实现图形算法、数据结构遍历、文件格式转换以及代码分析时。 应用场景 图形算法&#xff1…...

onnx模型转换到rknn脚本

from rknn.api import RKNN ONNX_MODEL ./onnx_models/yolov5s_rm_transpose.onnx # platform"rk1808" platform "rv1109" RKNN_MODEL yolov5s_relu_{}_out_opt.rknn.format(platform) if __name__ __main__: add_perm False # 如果设置成True,则将模…...

防御恶意爬虫攻击

数据抓取爬虫 数据抓取爬虫是攻击者使用自动化脚本或工具在移动应用程序中抓取敏感数据的一种方式。这些爬虫可以定向抓取用户信息、产品列表、评论和评级等数据。攻击者可能会将这些数据用于非法目的,例如进行身份盗窃、诈骗活动或者卖给其他恶意方。 对于移动应用…...

【自动驾驶技术栈学习】2-软件《大话自动驾驶》| 综述要点总结 by.Akaxi

----------------------------------------------------------------------------------------------------------------- 致谢:感谢十一号线人老师的《大话自动驾驶》书籍,收获颇丰 链接:大话自动驾驶 (豆瓣) (douban.com) -------------…...

SRS视频服务器应用研究

1.SRS尝试从源码编译启动 1.1.安装ubuntu 下载镜像文件 使用VMWare安装,过程中出现蓝屏,后将VM的软件版本从15.5升级到17,就正常了。 1.2.更新ubuntu依赖...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...

Linux 下 DMA 内存映射浅析

序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...

【iOS】 Block再学习

iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...

webpack面试题

面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...

「Java基本语法」变量的使用

变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...

基于Uniapp的HarmonyOS 5.0体育应用开发攻略

一、技术架构设计 1.混合开发框架选型 (1)使用Uniapp 3.8版本支持ArkTS编译 (2)通过uni-harmony插件调用原生能力 (3)分层架构设计: graph TDA[UI层] -->|Vue语法| B(Uniapp框架)B --&g…...

npm安装electron下载太慢,导致报错

npm安装electron下载太慢,导致报错 背景 想学习electron框架做个桌面应用,卡在了安装依赖(无语了)。。。一开始以为node版本或者npm版本太低问题,调整版本后还是报错。偶尔执行install命令后,可以开始下载…...

使用homeassistant 插件将tasmota 接入到米家

我写一个一个 将本地tasmoat的的设备同通过ha集成到小爱同学的功能,利用了巴法接入小爱的功能,将本地mqtt转发给巴法以实现小爱控制的功能,前提条件。1需要tasmota 设备, 2.在本地搭建了mqtt服务可, 3.搭建了ha 4.在h…...