1. 概述

在这个教程中,我们将学习如何在Gradle项目中配置条件依赖。

2. 项目设置

我们将为演示创建一个多模块项目。请访问Spring Initializr,创建我们的根项目conditional-dependency-demo。我们将使用Gradle、Java以及Spring Boot。

我们还会添加两个提供者模块provider1provider2,以及两个消费者模块consumer1consumer2

3. 配置条件依赖

假设基于项目属性,我们希望包含两个提供者模块中的一个。对于consumer1模块,如果指定了isLocal属性,则包含provider1模块。否则,应包含provider2模块。

要在consumer1模块的gradle.settings.kts文件中实现这一点,请添加以下内容:

plugins {
    id("java")
}

group = "com.baeldung.gradle"
version = "0.0.1-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
    testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.7.0")

    if (project.hasProperty("isLocal")) {
        implementation("com.baeldung.gradle:provider1")
    } else {
        implementation("com.baeldung.gradle:provider2")
    }
}

tasks.getByName<Test>("test") {
    useJUnitPlatform()
}

现在运行dependencies任务查看选择了哪个提供者模块:

gradle -PisLocal dependencies --configuration implementation
> Task :consumer1:dependencies

------------------------------------------------------------
Project ':consumer1'
------------------------------------------------------------

implementation - Implementation only dependencies for source set 'main'. (n)
\--- com.baeldung.gradle:provider1 (n)

(n) - Not resolved (configuration is not meant to be resolved)

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 591ms
1 actionable task: 1 executed

如我们所见,传递了属性导致包含了provider1模块。现在不指定任何属性运行dependencies任务:

gradle dependencies --configuration implementation
> Task :consumer1:dependencies

------------------------------------------------------------
Project ':consumer1'
------------------------------------------------------------

implementation - Implementation only dependencies for source set 'main'. (n)
\--- com.baeldung.gradle:provider2 (n)

(n) - Not resolved (configuration is not meant to be resolved)

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 649ms
1 actionable task: 1 executed

正如我们所见,现在provider2被包含。

4. 通过模块替换配置条件依赖

让我们看看另一种通过依赖替换来条件配置依赖的方法。对于consumer2模块,如果指定了isLocal属性,我们想要包含provider2模块。否则,应使用provider1模块。

为了实现这个目标,我们需要在consumer2模块中添加以下配置:

plugins {
    id("java")
}

group = "com.baeldung.gradle"
version = "0.0.1-SNAPSHOT"

repositories {
    mavenCentral()
}

configurations.all {
    resolutionStrategy.dependencySubstitution {
        if (project.hasProperty("isLocal"))
            substitute(project("com.baeldung.gradle:provider1"))
              .using(project(":provider2"))
              .because("Project property override(isLocal).")
    }
}

dependencies {
    implementation(project(":provider1"))

    testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
}

tasks.getByName<Test>("test") {
    useJUnitPlatform()
}

再次运行相同的命令,我们应该得到类似的结果。首先,带isLocal属性运行:

gradle -PisLocal dependencies --configuration compilePath
> Task :consumer2:dependencies

------------------------------------------------------------
Project ':consumer2'
------------------------------------------------------------

compileClasspath - Compile classpath for source set 'main'.
\--- project :provider1 -> project :provider2

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

确实,我们看到provider1项目被替换为provider2项目。现在不指定属性试一下:

gradle dependencies --configuration compilePath
> Task :consumer2:dependencies

------------------------------------------------------------
Project ':consumer2'
------------------------------------------------------------

compileClasspath - Compile classpath for source set 'main'.
\--- project :provider1

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 623ms
1 actionable task: 1 executed

正如预期,这次没有替换发生,provider1被包含。

5. 两种方法之间的差异

如上所述演示,两种方法都帮助我们实现了有条件地配置依赖的目标。让我们讨论一下两种方法之间的一些差异。

首先,直接在配置中编写条件逻辑看起来更简单,配置也较少,与第二种方法相比。

其次,尽管第二种方法涉及更多的配置,但它似乎更具语义性。 在第二种方法中,我们利用了Gradle本身提供的替换机制。它还允许我们指定替换的原因。此外,在日志中,我们可以注意到替换过程的发生,而在第一种方法中,这种信息是不可见的:

compileClasspath - Compile classpath for source set 'main'. 
\--- project :provider1 -> project :provider2

请注意,在第一种方法中,不需要进行依赖解析。仅通过以下命令即可获取结果:

gradle -PisLocal dependencies --configuration implementation

而在第二种方法中,如果我们检查implementation配置,将不会看到预期的结果。原因在于它只在依赖解析时工作。因此,它在compilePath配置中可用:

gradle -PisLocal dependencies --configuration compilePath

6. 总结

至此,本文已结束。在这篇文章中,我们了解了在Gradle中配置条件依赖的两种方法,并分析了它们之间的区别。

Gradle提供的依赖替换配置似乎更为常用。如往常一样,完整的代码和Gradle配置可在GitHub上找到。


» 下一篇: Java Weekly, 第451期