如何在Gradle中配置条件依赖

2025/04/30

1. 概述

在本教程中,我们将了解如何在Gradle项目中配置条件依赖。

2. 项目设置

我们将为演示建立一个多模块项目,首先访问start.spring.io并创建根项目conditional-dependency-demo,我们将使用Gradle、Java以及Spring Boot。

我们还添加两个提供者模块,provider1和provider2,以及两个消费者模块,consumer1和consumer2:

3. 配置条件依赖

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

为此,我们在consumer1模块的gradle.settings.kts文件中添加以下内容:

plugins {
    id("java")
}

group = "cn.tuyucheng.taketoday.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("cn.tuyucheng.taketoday.gradle:provider1")
    } else {
        implementation("cn.tuyucheng.taketoday.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)
\--- cn.tuyucheng.taketoday.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)
\--- cn.tuyucheng.taketoday.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 = "cn.tuyucheng.taketoday.gradle"
version = "0.0.1-SNAPSHOT"

repositories {
    mavenCentral()
}

configurations.all {
    resolutionStrategy.dependencySubstitution {
        if (project.hasProperty("isLocal"))
            substitute(project("cn.tuyucheng.taketoday.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

而在第二种方法中,如果我们检查实现配置,我们将看不到预期的结果,原因是它仅在依赖解析发生时才有效。因此,它可以通过compilePath配置来实现:

gradle -PisLocal dependencies --configuration compilePath

6. 总结

在本文中,我们了解了在Gradle中条件配置依赖的两种方法,并分析了两者之间的区别。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章