Page 129 - 《软件学报》2025年第7期
P. 129
3050 软件学报 2025 年第 36 卷第 7 期
同的依赖范围, 而不同依赖范围之间的误用造成的危害也不尽相同. 因此, 此类异味有大量触发场景和对应的危
害. 我们分别选取 Maven 和 Gradle 中主要的依赖范围, 将不同依赖范围之间误用所对应的危害列于表 5 和表 6
中, 其中, 表行代表依赖库的预期依赖范围, 表列代表实际依赖范围, 表的内容是出现实际和预期依赖范围不一致
时可能造成的后果. 从表中可以看出, 依赖范围误用可能造成许多种类的危害. 接下来我们将结合实例, 分别举例
介绍依赖范围误用对模块自身运行和下游模块构建可能造成的危害和对应的具体触发场景.
import lib2.A
A classA = new mod 直接使用传递依赖 lib2 中的类 A
A(); 但未在配置文件中声明
包含代码
lib2.A
依赖于 依赖于 包含类
public class A {
...
}
模块 mod 依赖库 lib1: 4.0.0 依赖库 lib2
不再依赖 lib2
升级 lib1
mod 在 lib1 升级后无法获取 lib2 构建错误
(a) 类型 1.4 依赖库 lib1: 4.0.1
依赖于 包含类 lib.A
public class A {
...
模块 mod 依赖库 lib: compileOnly }
包含代码
compileOnly 代表 lib
import lib.A 不会在运行时出现
A classA = new A(); 运行时错误
(b) 类型 1.6 但 lib 中的 A 会在运行时被使用
依赖于 依赖于 implementation 代表 lib
不会在 client 构建时出现
下游模块 client 模块 mod 依赖库 lib: implementation
包含类 包含类 包含类
client.C mod.B lib.A
import mod.B import lib1.A public class A {
public class C extends B { public class B extends A { ...
... ... } 但由于类 A 是类 C 的父类,
} } 下游模块
client 构建时需要 lib 中的类 A 构建错误
(c) 类型 1.6
依赖于 依赖于 runtime 代表 lib2
应该在 lib1 的运行时出现
模块 mod 依赖于 依赖库 lib1 依赖库 lib2: runtime
但由于依赖范围 runtime 被 test 覆盖, 运行时错误
(d) 类型 1.7 依赖库 lib2: test lib2 最终只会在测试时出现
图 4 造成危害的依赖异味案例
表 5 Maven 中依赖范围误用的触发场景和危害
预期范围
实际范围
compile runtime provided test
compile - 2, 7 5, 9 2, 5, 7, 9
runtime 1 - 1 5, 9
provided 3, 6, 8 3, 8 - 2
test 1 3, 8 1 -
表 6 Gradle 中依赖范围误用的触发场景和危害
预期范围
实际范围
api implementation runtimeOnly compileOnly test
api - 7 2, 7 5, 9 2, 5, 7, 9
implementation 6 - 2, 7 5, 9 2, 5, 7, 9
runtimeOnly 1 1 - 1 5, 9
compileOnly 3, 8 3, 8 3, 8 - 2
test 1 1 3, 8 1 -

