1. Overview
1.概述
In this tutorial, we’ll see how we can configure conditional dependencies in our Gradle projects.
在本教程中,我们将看到如何在我们的Gradle项目中配置条件性依赖。
2. Project Setup
2.项目设置
We’ll be setting up a multi-module project for the demonstration. Let’s head over to start.spring.io and create our root project conditional-dependency-demo. We’ll use Gradle and Java along with Spring Boot.
我们将为演示建立一个多模块项目。让我们前往start.spring.io并创建我们的根项目conditional-dependency-demo。我们将使用Gradle和Java,以及Spring Boot。
Let’s also add two provider modules, provider1 and provider2, and two consumer modules, consumer1 and consumer2:
让我们也添加两个提供者模块,provider1和provider2,以及两个消费者模块,consumer1和consumer2:
3. Configuring Conditional Dependency
3.配置条件依赖性
Let’s say, based on a project property, we want to include one of the two provider modules. For our consumer1 module, we want to include the provider1 module if the property isLocal is specified. Otherwise, the provider2 module should be included.
比方说,基于一个项目属性,我们想包括两个供应商模块中的一个。对于我们的consumer1模块,如果属性isLocal被指定,我们想包括provider1模块。否则,应该包括provider2模块。
To do this, let’s add the following in the gradle.settings.kts file of the consumer1 module:
要做到这一点,让我们在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()
}
Now, let’s run the dependencies task to see which provider module is being picked:
现在,让我们运行依赖性任务,看看哪个供应商模块被选中。
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
As we can see, passing the property led to the inclusion of the provider1 module. Let’s now run the dependencies task without any property specified:
正如我们所看到的,通过该属性导致了provider1模块的包含。现在让我们在不指定任何属性的情况下运行依赖关系任务。
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
As we can see, provider2 is now being included.
我们可以看到,provider2现在被包括在内。
4. Configuring Conditional Dependency via Module Substitution
4.通过模块置换配置条件依赖性
Let’s look at another approach to conditionally configure the dependency via dependency substitution. For our consumer2 module, we want to include the provider2 module if the isLocal property is specified. Otherwise, module provider1 should be used.
让我们来看看另一种通过依赖性替换来有条件地配置依赖性的方法。对于我们的consumer2模块,如果isLocal属性被指定,我们希望包含provider2模块。否则,应该使用模块provider1。
Let’s add the following configuration to our consumer2 module to achieve this goal:
让我们在我们的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()
}
Now, if we run the same commands again, we should get similar results. Let’s first run with the isLocal property specified:
现在,如果我们再次运行同样的命令,我们应该得到类似的结果。让我们首先在指定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
And sure enough, we see the provider1 project being substituted by the provider2 project. Let’s now try this without the property specified:
果然,我们看到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
As expected, no substitution took place this time, and provider1 was included.
正如预期的那样,这次没有发生替换,供应商1被包括在内。
5. Difference Between the Two Approaches
5.两种方法的区别
As we saw in the demonstrations above, both approaches helped us achieve our goal of conditionally configuring dependencies. Let’s talk about some of the differences between the two approaches.
正如我们在上面的演示中看到的,这两种方法都帮助我们实现了有条件地配置依赖关系的目标。让我们来谈谈这两种方法的一些区别。
First, writing the conditional logic directly looks simpler with less configuration as compared to the second approach.
首先,与第二种方法相比,直接编写条件逻辑看起来更简单,配置更少。
Secondly, although the second approach involved more configuration, it seems more idiomatic. In the second approach, we make use of the substitution mechanism provided by Gradle itself. It also allows us to specify a reason for substitution as well. Moreover, in the logs, we can notice the substitution taking place, unlike in the first approach where no such information is available:
其次,尽管第二种方法涉及更多的配置,但它似乎更符合习惯。在第二种方法中,我们利用了Gradle本身提供的替换机制。它还允许我们指定一个替换的理由。此外,在日志中,我们可以注意到正在发生的替换,而不像第一种方法那样没有这种信息。
compileClasspath - Compile classpath for source set 'main'.
\--- project :provider1 -> project :provider2
Let’s also notice that in the first approach, dependency resolution wasn’t required. We can get the results with:
我们还注意到,在第一种方法中,不需要进行依赖性解析。我们可以用以下方法得到结果。
gradle -PisLocal dependencies --configuration implementation
While in the second approach, if we were to check the implementation configuration, we won’t see the expected results. The reason being it only works when the dependency resolution takes place. Hence, it was available with compilePath configuration:
而在第二种方法中,如果我们要检查implementation配置,我们就不会看到预期的结果。原因是它只在依赖性解析发生时起作用。因此,它可以用compilePath配置。
gradle -PisLocal dependencies --configuration compilePath
6. Conclusion
6.结论
With that, we can conclude this article. In this article, we saw two approaches to configure dependencies conditionally in Gradle. We also analyzed the difference between the two.
就这样,我们可以结束这篇文章了。在这篇文章中,我们看到了两种在Gradle中有条件地配置依赖关系的方法。我们还分析了两者之间的区别。
The dependency substitution configuration provided with Gradle appeared to be the more idiomatic approach. As always, the complete code and Gradle configurations are available over on GitHub.
Gradle提供的依赖替换配置似乎是更习惯的方法。一如既往,完整的代码和Gradle配置可在GitHub上获得< data-saferedirecturl=”https://www.google.com/url?q=http://thelink.com/&source=gmail&ust=1640234878959000&usg=AOvVaw30romyOBJxqLz0Fo0Ry2P-” href=”https://github.com/eugenp/tutorials/tree/master/gradle-modules/gradle-7″ rel=”noopener” target=”_blank” >。