⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 程序员波特 「potter」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

臃肿的 Maven 项目

在 Java 项目开发中,Maven 作为强大的项目管理和构建工具,极大地简化了依赖管理和项目构建过程。但随着项目的不断演进,依赖的 Jar 包越来越多,我们的 Maven 项目也逐渐变得臃肿不堪。

曾经,我参与维护一个大型的 Spring Boot 项目,随着业务功能的不断迭代,新的功能需求不断涌现,开发过程中,为了实现特定的功能,开发人员不断地向项目中添加各种依赖。

在一次版本迭代中,为了实现文件上传和下载功能,引入了一个功能强大的文件处理库,然而这个库本身又依赖于多个其他的 Jar 包,这些间接依赖也随之被引入到项目中。随着类似的功能不断增加,项目的依赖树变得越来越复杂。

当我接手这个项目时,发现构建项目的速度变得极慢,每次执行mvn clean install命令,都需要漫长的等待时间。有一次紧急修复线上问题,需要快速构建并部署项目,结果因为构建时间过长,导致修复上线时间延迟,给业务带来了一定的影响。

此外,项目打包后的 Jar 包体积也变得非常大,原本几十 MB 的 Jar 包,如今已经飙升到几百 MB,这不仅增加了项目部署的时间和成本,也给服务器的存储和传输带来了压力。而且,在项目的日常维护中,由于依赖过多,依赖冲突的问题也时常出现,每次排查和解决这些冲突都需要耗费大量的时间和精力。

这些问题严重影响了项目的开发效率和部署速度,也给项目的维护带来了很大的挑战。因此,简化 Maven 项目依赖,去除未使用的 Jar 包,成为了亟待解决的问题。

为什么要去除未使用的 Jar 包

在项目开发过程中,未使用的 Jar 包就像是房间里堆积的杂物,看似无害,实则带来诸多问题。

  • 占用存储空间:每一个 Jar 包都会占用一定的磁盘空间,随着项目中未使用 Jar 包的不断积累,它们所占用的空间也会越来越大。在一个大型的企业级项目中,可能会依赖成百上千个 Jar 包,其中未使用的 Jar 包可能占据了几十甚至上百 MB 的空间。这不仅会浪费宝贵的磁盘资源,还可能影响服务器的存储性能。
  • 影响构建速度:Maven 在构建项目时,需要处理所有依赖的 Jar 包。未使用的 Jar 包会增加构建过程中依赖解析和下载的时间,从而导致项目构建速度变慢。想象一下,每次修改代码后都需要漫长的等待才能完成构建,这无疑会极大地影响开发效率。在持续集成和持续部署(CI/CD)的流程中,缓慢的构建速度还会导致整个部署流程的延迟,影响项目的交付进度。
  • 增加维护难度:过多的 Jar 包会使项目的依赖关系变得复杂,难以理清。当项目需要升级某个依赖或者排查问题时,过多的未使用 Jar 包会增加排查的难度和工作量。在一个涉及多个模块和团队协作的项目中,不同的开发人员可能引入了一些暂时或不再使用的依赖,随着时间的推移,这些依赖会让整个项目的依赖关系变得混乱不堪,后续维护人员在理解和管理这些依赖时会面临很大的挑战。
  • 可能引发依赖冲突:不同的 Jar 包可能依赖同一个库的不同版本,当这些 Jar 包同时存在于项目中时,就容易引发依赖冲突,导致程序运行出错。例如,项目中同时引入了两个不同的日志框架依赖,它们可能对日志接口的实现方式不同,从而在运行时引发冲突,导致日志记录异常或程序崩溃 。

怎么做?Maven 依赖分析工具登场

好在 Maven 为我们提供了一些实用的工具和方法,帮助我们分析和管理依赖,找出并去除那些未使用的 Jar 包。

Maven 自带的dependency:tree插件就可以帮我们查看项目的依赖树,了解每个依赖的来源和传递关系。在项目的根目录下,打开命令行终端,执行mvn dependency:tree命令,Maven 就会输出项目的依赖树。比如,下面是ruoyi-cloud 开源项目的部分依赖树输出 :

从这个依赖树中,我们可以清晰地看到每个依赖的层级关系和作用范围。通过仔细分析这个依赖树,我们可以初步判断哪些依赖可能是未使用的

解读分析结果

执行mvn dependency:analyze命令后,我们会得到一个详细的依赖分析报告,报告中主要包含两个重要部分:Used undeclared dependencies found和Unused declared dependencies found。下面我们来详细解读这两部分内容。

Used undeclared dependencies found 这一部分指的是项目中实际使用了某个依赖包,但并未在pom.xml文件中显式声明。这些依赖包可能是通过其他依赖间接引入的。

Unused declared dependencies found 这一部分则是指你在项目的pom.xml文件中声明了某个依赖包,但在实际的项目代码中并未使用到它。这些依赖包可能是不必要的,可以考虑从pom.xml中移除。

对于这些未使用的依赖,我们可以考虑从pom.xml文件中移除,以简化项目的依赖关系 。但是,在删除这些依赖之前,我们需要注意以下几点 :

  • “未使用” 的定义范围:这里所说的 “未使用” 仅限main/java和test源代码目录,不包括配置文件或其他可能的扩展点。有些依赖可能在配置文件中被引用,或者通过其他方式被项目所依赖,虽然在代码中没有直接使用,但实际上是项目正常运行所必需的。比如,在一个 Spring Boot 项目中,application.yml配置文件中可能配置了数据库连接信息,依赖于mysql-connector-java这个依赖包。虽然在代码中没有直接使用该依赖包中的类,但它对于项目连接数据库是必不可少的,因此不能随意删除。
  • 备份pom.xml文件:在删除依赖之前,务必备份pom.xml文件。以防万一误删了重要依赖,导致项目无法正常运行。这样,在出现问题时,我们可以及时恢复到之前的依赖配置。
  • 依赖分析工具的局限性:Maven 的依赖分析工具并非万能的,有时可能会产生误报。例如,某些工具可能无法识别某些特殊的使用场景,如注解处理器等。有些依赖可能是通过注解处理器在编译时起作用的,在运行时并没有直接的代码引用,依赖分析工具可能会将其误判为未使用的依赖。因此,在删除任何依赖后,都应进行充分的测试,包括单元测试、集成测试等,以验证项目的稳定性 。如果项目在删除依赖后出现了编译错误或运行时异常,我们需要仔细排查原因,确定是否是因为删除了必要的依赖所导致的。

清理依赖的最佳时机

新项目初始化时

在新项目初始化阶段,每一次依赖的添加都像是为项目大厦奠定基石,务必慎之又慎。很多开发者在创建新项目时,为了图方便,常常一股脑地复制旧项目的依赖配置 。但不同项目的业务需求和功能特点千差万别,盲目复制会导致项目从一开始就背负着不必要的负担 。

比如,一个简单的后端数据处理项目,却引入了大量前端开发相关的依赖,这些多余的依赖不仅占用存储空间,还会增加项目构建的时间和复杂性 。因此,在新项目初始化时,我们应该根据项目的实际需求,仔细评估每一个依赖的必要性,只引入真正需要的 Jar 包。这样可以从源头上避免依赖臃肿的问题,为项目的后续发展奠定良好的基础。

功能代码重构时

当项目进行功能代码重构时,也是清理依赖的绝佳时机。重构的过程通常涉及对代码结构和逻辑的优化,这时候很多旧的功能被修改或删除,与之相关的依赖可能也不再被使用。

在重构过程中顺便审查和清理依赖,就像是在整理房间的同时扔掉不再需要的杂物 ,可以使项目更加整洁和高效 。而且,由于重构之后通常会有自测和提测等环节,如果在清理依赖的过程中不小心误删了重要的依赖,也能在后续的测试环节中及时发现并修复。

例如,在一个电商项目中,对订单管理模块进行重构时,发现原来用于实现订单导出为 Excel 功能的依赖,在新的实现方案中不再被使用。此时,就可以在重构的过程中,将这个依赖从pom.xml文件中移除 ,并通过后续的测试来确保项目的正常运行。

补充一个快捷方法

在 IDEA 中,我们也可以方便地查看依赖树。打开项目的pom.xml文件,在右侧的 Maven 工具窗口中,找到项目节点,展开后右键点击,选择Show Dependencies,IDEA 就会以图形化的方式展示项目的依赖关系,更加直观地帮助我们分析依赖。

文章目录
  1. 1. 臃肿的 Maven 项目
  2. 2. 为什么要去除未使用的 Jar 包
  3. 3. 怎么做?Maven 依赖分析工具登场
    1. 3.0.1. 解读分析结果
  • 4. 清理依赖的最佳时机
    1. 4.0.1. 新项目初始化时
    2. 4.0.2. 功能代码重构时
  • 5. 补充一个快捷方法