Page 122 - 《软件学报》2025年第7期
P. 122
孙伟杰 等: Java 依赖异味的实证研究与统一检测技术 3043
我们的研究及其配套检测工具 JDepAna 具有显著的实际应用价值.
总的来说, 本文主要做出以下贡献: (1) 发现了 Java 项目依赖管理中可能存在的 13 类依赖异味; (2) 设计了适
用于 Maven 和 Gradle 项目依赖管理的依赖模型, 并提出了针对各种依赖异味的检测算法; (3) 实现了同时适配于
Maven 和 Gradle 的依赖异味检测工具 JDepAna, 并通过实验证明了其有效性和实用性.
本文第 1 节介绍 Java 项目依赖管理中的基本概念. 第 2 节介绍针对 Java 项目中依赖异味进行的实证研究以
及经过研究获得的 Java 依赖管理中可能存在的依赖异味和对应影响. 第 3 节基于实证研究结果, 介绍依赖异味的
检测流程和检测工具的具体实现. 第 4 节介绍对前述检测工具的检测效果的实验评估和实验过程中的效度威胁
性. 第 5 节介绍相关研究工作. 第 6 节对全文进行总结, 并对未来研究工作进行展望.
1 背 景
为了便于后续讨论, 本节将介绍 Java 项目的依赖管理和常用构建工具 Maven 和 Gradle 的依赖解析机制.
1.1 Java 项目依赖管理
Java 项目广泛使用 Maven 和 Gradle 进行依赖管理. 作为两种主流的构建工具, 它们的构建最小单元都是模
块 (module). 每个模块包含其专属的源代码、测试代码及配置文件 (Maven 对应 pom.xml, Gradle 对应 build.
gradle). 这些模块在构建过程中生成的构件 (artifact) 通常是 JAR 文件, 通过三元组标识符 (G:A:V) 予以区分, 分别
对应组织名称 (G)、构件名称 (A) 及版本信息 (V). 在配置文件中, 模块同样以 (G:A:V) 的形式声明源代码和测试
代码中所使用的依赖库. 配置文件中声明的依赖库依据其功能角色, 在不同的使用场景下发挥作用, 如被用于源代
码编译或进行测试. Maven 和 Gradle 都提供了依赖库的对应配置选项, 供开发者精细化控制依赖库的使用场景
(主要包括构建、运行和测试这 3 类使用场景), 我们称这类依赖库的配置为依赖范围 (dependency scope). 例如
Maven 中的依赖范围 compile 就对应着构建、运行和测试这 3 类使用场景. Maven 和 Gradle 会解析配置文件, 获
取模块所需的依赖库, 并构建模块的依赖树. 依赖树展示了模块所依赖的外部库及其相互关系, 包括主动引入的依
赖 (直接依赖) 和由直接依赖引入的其他依赖库 (传递依赖).
在单一模块之外, 多模块 (multi-module) 项目同样是构建复杂 Java 应用程序的常见模式. 这种结构设计允许
项目按功能或服务划分成多个独立的模块, 每个模块专注于特定任务的开发、测试与维护, 最终所有模块协同工
作, 共同构建出一个完整且功能丰富的应用程序. 多模块项目体系通常围绕一个中心父项目构建, 该父项目虽然本
身不承载业务逻辑代码, 却扮演着配置中心的角色, 通过集中管理的配置文件来统辖各子模块的构建行为与依赖
规则. 图 1 展示了一个典型的多模块 Maven 项目结构及其依赖管理方式.
EFQFOEFODJFT
EFQFOEFODZ
依赖库 HSPVQ*E FYBNQMF HSPVQ*E
BSUJGBDU*E MJC BSUJGBDU*E
配置 声明 WFSTJPO WFSTJPO
TDPQF UFTU TDPQF
EFQFOEFODZ
包括 模块 mod1 配置文件 pom.xml EFQFOEFODJFT
依赖库 EFQFOEFODJFT 继承项目中版本配置
包括 配置 声明 EFQFOEFODZ
HSPVQ*E FYBNQMF HSPVQ*E
BSUJGBDU*E MJC BSUJGBDU*E
WFSTJPO WFSTJPO
模块 mod2 配置文件 pom.xml TDPQF UFTU TDPQF
EFQFOEFODZ
项目 pr 依赖库
依赖库 EFQFOEFODJFT
配置
声明 EFQFOEFODZ.BOBHFNFOU
EFQFOEFODJFT 继承
EFQFOEFODZ
配置文件 pom.xml HSPVQ*E FYBNQMF HSPVQ*E
BSUJGBDU*E MJC BSUJGBDU*E
WFSTJPO WFSTJPO
EFQFOEFODZ
EFQFOEFODJFT
EFQFOEFODZ.BOBHFNFOU
图 1 使用 Maven 的多模块项目
从图 1 中可以看到, 项目 pr 包含两个模块 mod1 和 mod2, 每个模块都有自己的配置文件 pom.xml. 在这些配
置文件中, 开发者需要声明所需的依赖库, 并指定其版本和范围. 例如, 模块 mod1 和 mod2 都依赖于 example:lib:

