Page 123 - 《软件学报》2025年第7期
P. 123

3044                                                       软件学报  2025  年第  36  卷第  7  期


                 1.0.0  这个库. 值得注意的是, 项目    pr 的配置文件    pom.xml 中包含<dependencyManagement>标签, 用于统一管理依
                 赖版本. 这样一来, mod1    和  mod2  可以继承这个版本信息, 而不需要在各自的           pom.xml 文件中重复声明版本号.
                    为了确保     Java  项目在不同环境中的构建一致性和可重现性, Maven                和  Gradle  提供了构建工具封装器
                 (wrapper) 来启动相应版本的构建工具. 封装器包括启动脚本和               JAR  文件  (Maven  使用  maven-wrapper.jar, Gradle
                 使用  gradle-wrapper.jar). 在构建工具封装器正常工作的情况下, 开发者无须在本地安装               Maven  和  Gradle, 只需运
                 行脚本, 即可调用对应的       JAR  文件, 自动下载并使用相应版本的构建工具.

                 1.2   构建工具依赖解析机制

                    Maven  和  Gradle 极大地简化了依赖管理的复杂性. 开发者只需要在配置文件中对项目的直接依赖进行配置,
                 构建工具会对配置文件中声明的依赖库进行解析, 下载并管理所有的直接依赖和引入的间接依赖. 在解析过程中,
                 它们会遵循依赖仲裁       (dependency mediation) 机制来确保解析结果的一致性, 主要包括以下两点.
                    ● 版本仲裁机制: 当依赖树中出现同一依赖库的不同版本时, Maven                 和  Gradle 仅会选择其中一个版本, 并忽略
                 其他版本. Maven  使用“最短路径优先”策略, 优先选择依赖树中离模块最近的版本; 相比之下, Gradle 默认采用“最
                 高版本优先”策略, 在冲突时选择最高的版本. 例如, 在图               2(a) 中, 模块  mod  同时依赖于  lib:v1.0.0  和  lib:v2.0.0, 此
                 时  Maven  会选择距离较近的    lib:v1.0.0, 而  Gradle 则会选择版本较高的  lib:v2.0.0.


                                                              Maven      Gradle
                                                依赖于
                                                               选择 v1.0.0  选择 v2.0.0
                                                      依赖库 lib1: v1.0.0
                                          模块 mod 依赖于
                                                             依赖于
                                          (a)         依赖库 lib2  依赖库 lib1: v2.0.0
                                                依赖于
                                                     依赖库 lib1: test
                                          模块 mod 依赖于
                                                             依赖于
                                          (b)         依赖库 lib2  依赖库 lib1: compile
                                                   图 2 构建工具解析机制

                    ● 范围仲裁机制: 当依赖树中出现同一依赖库的不同依赖范围时, Maven                    仅会选择直接依赖的范围而忽略传
                 递依赖的范围. 例如, 在图      2(b) 中, 依赖库  lib  既是直接依赖又是间接依赖, 其作为直接依赖的范围与作为传递依
                 赖的范围不一致, 最终传递依赖的范围会被忽略.

                 2   依赖异味的实证研究

                    为了深入研究      Java 项目依赖管理中潜藏的问题, 我们针对           Java 项目中可能存在的依赖异味及其影响开展实
                 证研究. 接下来我们将介绍数据收集流程并展示研究结果.
                    ● RQ1: Java 项目中可能存在哪些依赖异味类别?
                    ● RQ2: 这些依赖异味会在什么情境下产生怎样的危害?
                    为了回答    RQ1  和  RQ2, 我们选择了  3  类调研对象, 分别是官方文档、学术论文和开源社区. 我们从官方文档
                 和学术论文中总结出关键词, 根据关键词从开源社区中搜索问题报告, 在人工分析后最终筛选出                              47  个依赖异味相
                 关问题报告. 下面我们将详细介绍数据收集过程和调研结果.

                 2.1   数据收集
                    步骤  1: 收集相关问题报告. 为了全面调研          Java 项目依赖管理中潜藏的问题, 我们选择了以下              3  类调研对象:
                 (1) 官方文档: Maven、Gradle 的依赖管理手册       [15,16] ; (2) 学术论文: 依赖管理相关的论文   [7−14,17−29] ; (3) 开源社区:
   118   119   120   121   122   123   124   125   126   127   128