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

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


                 的特性, 但却在配置文件中进行声明. 而           Maven  和  Gradle 在将  mod  打包为可执行  JAR  时, 所有的依赖库都会被涵
                 盖, 包括实际上并未被使用的         lib, 导致构建产物冗余.

                                 import lib2.A
                                                mod 直接使用传递依赖 lib2
                                 A classA = new A();  中的类但未在配置文件中声明                  构建错误
                                   包含代码
                                                                       lib2.A
                                     依赖于        依赖于        包含类      public class A {
                                                                       ...
                                                                    }
                                 模块 mod  依赖库 lib1:v4.0.0  依赖库 lib2
                                     如果升级至
                                                 不再                     无法访达 lib2 中的类
                                                                        由于 lib 升级, mod
                                                 依赖于
                              (a) 危害 1   依赖库 lib1:v4.0.1
                               Class c=Class.forName(“lib2.A”);  mod 直接使用传递依赖 lib2 中  运行时错误
                                                   的类但未在配置文件中声明
                                   包含代码
                                                                       lib2.A
                                     依赖于        依赖于        包含类      public class A {
                                                                       ...
                                                                    }
                                 模块 mod  依赖库 lib1: v4.0.0  依赖库 lib2
                                     如果升级至                           由于 lib 升级,
                                                不再 依赖于           mod 无法访达 lib2 中的类
                              (b) 危害 3   依赖库  lib1: v4.0.1
                              import lib2.A
                                                 mod 直接使用传递依赖 lib2
                              A class A = new A ();                              运行时语义冲突
                              String lib2Ver= A.getVersion ();  中的类但未在配置文件中声明
                                   包含代码                                 Lib2.A
                                                                   public class A{
                                     依赖于        依赖于        包含类      String getVersion (){
                                                                      return “V1”
                                                                    }
                                 模块 mod  依赖库 lib1: v4.0.0  依赖库 lib2: v1.0.0  }
                                     如果升级至
                                                                       Lib2.A
                                                依赖于        包含类     public class A{
                                                                    String getVersion (){
                                                                      return “V2”
                                                                    }
                                        依赖库 lib1: v4.0.1  依赖库 lib2: v2.0.0  }
                              (c) 危害 4                 lib2 从 v1.0.0 升级至 v2.0.0
                                            图 A6 异味   1.4  可能危害与对应触发场景

                    (3) 下游模块构建时间增加: 这类危害在出现依赖未使用时始终存在. 以图                     A7(c) 为例, 模块  mod  并未使用依
                 赖库  lib  中的特性, 但却在配置文件中进行声明. 下游模块            client 在使用模块  mod  的同时, 也就引入了    mod  的依赖
                 库  lib  作为传递依赖, 其会在构建时被引入, 需要从中央存储仓库获取对应依赖库, 进而导致构建时间增加, 即增加
                 下游模块   client 的构建成本.
                    (4) 下游模块构建产物冗余: 其触发场景为下游模块可执行                 JAR  的打包. 以图  A7(d) 为例, 模块  mod  并未使用
                 依赖库   lib  中的特性, 但却在配置文件中进行声明. 下游模块           client 在使用模块  mod  的同时, 也引入了    mod  的依赖
                 库  lib  作为传递依赖, 而  Maven  和  Gradle 在将  client 打包为可执行  JAR  时, 所有直接依赖和传递依赖库都会被包
                 括, 导致下游模块     lib  构建产物冗余.
                    6) 类别  1.6  依赖范围误用
                    Maven  与  Gradle 均定义了多种依赖范围, 若未按预期正确使用这些范围, 可能引发多种类型的危害. 我们在
                 正文表   5  和表  6  中对这些危害进行了梳理. 下文将详细阐述正文中未能详述的各类危害及其触发场景.
                    (1) 构建错误: 以预期依赖范围为        compile, 实际范围为   test 为例, 在图  A8(a) 中, 模块  mod  在源码中直接引用
                 lib  中的类  A, 因此其预期依赖范围应该是        compile, 但其实际依赖范围被设置为        test, 代表其只会在测试时出现而
                 不会在构建时出现, 这就导致         mod  构建时无法找到类     A, 最终构建错误.
                    (2) 构建时间增加: 以预期范围为        test, 实际范围为  compile 为例, 在图  A8(b) 中, 模块  mod  将直接依赖  lib  的依
   148   149   150   151   152   153   154   155   156   157   158