在多个项目上工作可能需要与多个不同版本的 Java 语言进行交互。即使在单个项目内部,由于向后兼容性要求,代码库的不同部分可能也固定在特定的语言级别。这意味着必须在构建项目的每台机器上安装和管理相同工具(即工具链)的不同版本。
一个 Java 工具链是一套用于构建和运行 Java 项目的工具集合,通常由环境通过本地 JRE 或 JDK 安装提供。编译 Task 可能使用 javac
作为其编译器,测试和执行 Task 可能使用 java
命令,而 javadoc
将用于生成文档。
默认情况下,Gradle 使用相同的 Java 工具链来运行 Gradle 本身并构建 JVM 项目。然而,这并非总是理想的。在不同的开发人员机器和 CI 服务器上使用不同的 Java 版本构建项目可能导致意外问题。此外,您可能希望使用不支持运行 Gradle 的 Java 版本来构建项目。
为了提高构建的可重现性并使构建要求更清晰,Gradle 允许在项目和 Task 级别配置工具链。您还可以使用 Daemon JVM 标准来控制用于运行 Gradle 本身的 JVM。
项目工具链
Gradle 提供了多种方法来配置用于编译和运行项目的 Java 版本。
五种主要机制是
这些设置并非互斥,高级用户可能需要在特定场景下结合使用它们。
1. Java 工具链
要为项目配置工具链,请在 java
扩展块中声明所需的 Java 语言版本
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
java
块非常灵活,支持额外的配置选项。您可以在使用 Java 工具链中了解更多信息。
2. --release
标志
对于严格的交叉编译,建议使用 --release
标志而不是 sourceCompatibility
和 targetCompatibility
tasks.withType<JavaCompile>().configureEach {
options.release = 8
}
tasks.withType(JavaCompile).configureEach {
options.release = 8
}
此标志可以防止意外使用指定版本中不可用的较新 API。但是,它并不控制使用哪个 JDK——只控制编译器如何处理源代码。
如果同时需要特定的 JDK 和严格的交叉编译,此方法可以与工具链结合使用。
3. Source 和 Target 兼容性
设置 sourceCompatibility
和 targetCompatibility
会告知 Java 编译器生成与特定 Java 版本兼容的字节码,但不会强制 Gradle 本身使用哪个 JDK 运行
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
这不能保证使用正确的 JDK,并且在 API 已向后移植到旧版 Java 时可能会导致问题。
仅当您需要向后兼容性但无法使用工具链时,才应使用此方法。
4. 环境变量 (JAVA_HOME
)
您可以通过设置 JAVA_HOME
环境变量来影响 Gradle 使用哪个 JDK
export JAVA_HOME=/path/to/java17
这为系统上的所有基于 Java 的工具(包括 Gradle 和 Maven)设置了一个默认 JDK。
这不会覆盖 Gradle 的工具链支持或其他项目特定配置。 |
这种方法对于不使用工具链并期望环境中某个特定 JDK 处于活动状态的遗留项目很有用。
然而,由于 JAVA_HOME
是全局生效的,它不能用于为不同的项目指定不同的 JDK 版本。使用 工具链更可靠,工具链允许在项目级别设置 Java 版本。
5. IDE 设置
大多数现代 IDE 允许您配置在处理项目时用于运行 Gradle 的 JVM。此设置会影响 Gradle 本身在 IDE 内部的执行方式,但不会影响代码的编译方式——除非构建未明确指定工具链。
如果您的构建未定义 Java 工具链,Gradle 可能会回退到使用 IDE 设置定义的 Java 版本。这可能导致意外且不可重现的行为,特别是如果不同的团队成员使用不同的 IDE 配置。
您应该更改 IDE 的 Gradle JVM 设置,使其与命令行上使用的 JVM(JAVA_HOME
或系统的默认 Java 安装)对齐——确保跨环境的一致行为(例如,从 IDE 与终端运行测试或 Task 时)。
如果 IDE 在未设置 JVM 或 JVM 与 JAVA_HOME
不匹配时发出警告/错误,您也应该更改 IDE 的 Gradle JVM 设置。
IntelliJ IDEA
配置 Gradle JVM
-
打开 Settings (Preferences) > Build, Execution, Deployment > Gradle。
-
将 Gradle JVM 设置为所需的 JDK。
Eclipse
配置 Gradle JVM
-
打开 Preferences > Gradle > Gradle JDK。
-
选择相应的 JDK。
某些 IDE 也允许您在相同的设置屏幕中配置 Gradle Daemon 的 JVM。请注意不要将其与工具链或项目 JVM 混淆——请确保您选择了正确的 JVM。 |
组合使用工具链
在某些情况下,您可能希望
-
使用特定 JDK 版本进行编译(通过
toolchains
)。 -
确保编译的字节码与旧版 Java 兼容(通过
--release
或targetCompatibility
)。
例如,要使用 Java 17 进行编译但生成 Java 11 字节码
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.withType<JavaCompile>().configureEach {
options.release = 11
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.withType(JavaCompile).configureEach {
options.release = 11
}
项目工具链设置对比表
方法 | 确保使用正确 JDK? | 自动下载 JDK? | 防止意外使用 API? |
---|---|---|---|
Java 工具链 |
✅ 是 |
✅ 是 |
❌ 否 |
|
❌ 否 |
❌ 否 |
✅ 是 |
Source 和 Target 兼容性 |
❌ 否 |
❌ 否 |
❌ 否 |
环境变量 ( |
✅ 是(但仅限于全局) |
❌ 否 |
❌ 否 |
IDE 设置 |
✅ 是(在 IDE 内部) |
❌ 否 |
❌ 否 |
建议
-
对于大多数用户: 使用 Java 工具链(
toolchain.languageVersion
)。 -
为了严格强制兼容性: 使用
--release
标志。 -
对于高级情况: 结合使用工具链和
--release
。 -
除非必要,避免使用
sourceCompatibility
和targetCompatibility
。 -
仅当您需要系统范围的默认 JDK 版本时,才使用
JAVA_HOME
。 -
如果您希望 Gradle 与 IDE 的 JDK 版本匹配,则使用 IDE 设置。
Task 工具链
如果您想调整特定 Task 使用的工具链,可以指定 Task 使用的确切工具。例如,Test
Task 暴露了一个 JavaLauncher
属性,用于定义启动测试时使用的 java 可执行文件。
在下面的示例中,我们将所有 Java 编译 Task 配置为使用 Java 8。此外,我们引入了一个新的 Test
Task,它将使用 JDK 17 运行我们的单元测试。
tasks.withType<JavaCompile>().configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(8)
}
}
tasks.register<Test>("testsOn17") {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.withType(JavaCompile).configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(8)
}
}
tasks.register('testsOn17', Test) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(17)
}
}
此外,在 application
子项目中,我们添加了另一个 Java 执行 Task,以便使用 JDK 17 运行我们的应用程序。
tasks.register<JavaExec>("runOn17") {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(17)
}
classpath = sourceSets["main"].runtimeClasspath
mainClass = application.mainClass
}
tasks.register('runOn17', JavaExec) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(17)
}
classpath = sourceSets.main.runtimeClasspath
mainClass = application.mainClass
}
根据 Task 的不同,JRE 可能就足够了,而对于其他 Task(例如编译),则需要 JDK。默认情况下,如果已安装的 JDK 能够满足要求,Gradle 会优先选择 JDK 而不是 JRE。
可以从 javaToolchains
扩展中获取工具链工具提供者。
有三个工具可用
-
JavaCompile Task 使用的工具
JavaCompiler
-
Javadoc Task 使用的工具
JavadocTool
与依赖 Java 可执行文件或 Java Home 的 Task 集成
任何可以通过 Java 可执行文件路径或 Java Home 位置配置的 Task 都可以从工具链中受益。
虽然您无法直接连接工具链工具,但它们都包含元数据,可以访问它们的完整路径或所属的 Java 安装路径。
例如,您可以按如下方式为 Task 配置 java
可执行文件
val launcher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(11)
}
tasks.sampleTask {
javaExecutable = launcher.map { it.executablePath }
}
def launcher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(11)
}
tasks.named('sampleTask') {
javaExecutable = launcher.map { it.executablePath }
}
另一个示例是,您可以按如下方式为 Task 配置 Java Home
val launcher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(11)
}
tasks.anotherSampleTask {
javaHome = launcher.map { it.metadata.installationPath }
}
def launcher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(11)
}
tasks.named('anotherSampleTask') {
javaHome = launcher.map { it.metadata.installationPath }
}
如果您需要特定工具(例如 Java 编译器)的路径,可以按如下方式获取:
val compiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(11)
}
tasks.yetAnotherSampleTask {
javaCompilerExecutable = compiler.map { it.executablePath }
}
def compiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(11)
}
tasks.named('yetAnotherSampleTask') {
javaCompilerExecutable = compiler.map { it.executablePath }
}
上面的示例使用了具有 RegularFileProperty 和 DirectoryProperty 属性的 Task,这允许延迟配置。执行 launcher.get().executablePath 、launcher.get().metadata.installationPath 或 compiler.get().executablePath 可以获取给定工具链的完整路径,但请注意,这可能会急切地实现(并配置)工具链。 |
使用 Java 工具链
使用 Java 工具链可以使 Gradle 自动下载并管理构建所需的 JDK 版本。它确保在编译和执行时都使用正确的 Java 版本。
您可以通过在 java
扩展块中指定 Java 语言版本来定义项目使用的工具链
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
现在执行构建(例如使用 gradle check
)将为您和运行构建的其他人处理以下几件事:
工具链支持在 Java 插件及其定义的 Task 中可用。 对于 Groovy 插件,支持编译但尚不支持 Groovydoc 生成。对于 Scala 插件,支持编译和 Scaladoc 生成。 |
按供应商选择工具链
如果您的构建对使用的 JRE/JDK 有特定要求,您可能还需要定义工具链的供应商。JvmVendorSpec
包含 Gradle 可识别的已知 JVM 供应商列表。优点是 Gradle 可以处理不同 JDK 版本中 JVM 编码供应商信息方式的任何不一致之处。
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.ADOPTIUM
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.ADOPTIUM
}
}
如果您想定位的供应商不是已知供应商,您仍然可以将工具链限制为与可用工具链的 java.vendor
系统属性匹配的工具链。
以下片段使用过滤来包含可用工具链的子集。此示例仅包含其 java.vendor
属性包含给定匹配字符串的工具链。匹配是按大小写不敏感的方式进行的。
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.matching("customString")
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.matching("customString")
}
}
选择支持 GraalVM native image 的工具链
如果您的项目需要具有 GraalVM Native Image 能力的工具链,您可以配置规范来请求它:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
nativeImageCapable = true
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
nativeImageCapable = true
}
}
将该值留空或设置为 false
不会根据 Native Image 能力限制工具链选择。这意味着如果符合其他标准,可以选择支持 Native Image 的 JDK。
按虚拟机实现选择工具链
如果您的项目需要特定的实现,您也可以根据实现进行过滤。目前可供选择的实现有:
VENDOR_SPECIFIC
-
作为占位符,匹配任何供应商的任何实现(例如 hotspot, zulu 等)
J9
-
仅匹配使用 OpenJ9/IBM J9 运行时引擎的虚拟机实现。
例如,要使用通过 AdoptOpenJDK 分发的 IBM JVM,您可以按照下面的示例指定过滤器。
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.IBM
implementation = JvmImplementation.J9
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.IBM
implementation = JvmImplementation.J9
}
}
Java 主版本、供应商(如果指定)和实现(如果指定)将作为编译和测试执行的输入进行跟踪。 |
配置工具链规范
Gradle 允许配置影响工具链选择的多个属性,例如语言版本或供应商。尽管这些属性可以独立配置,但配置必须遵循某些规则才能形成一个有效的规范。
在两种情况下,JavaToolchainSpec
被视为有效:
-
未设置任何属性,即规范为空;
-
设置了
languageVersion
,并且可选地设置了任何其他属性。
换句话说,如果指定了供应商或实现,则必须同时指定语言版本。Gradle 区分配置了语言版本的工具链规范和未配置语言版本的工具链规范。在大多数情况下,没有语言版本的规范将被视为选择当前构建所用工具链的规范。
自 Gradle 8.0 起,使用无效的 JavaToolchainSpec
实例会导致构建错误。
自动检测已安装的工具链
默认情况下,Gradle 会自动检测本地的 JRE/JDK 安装,因此用户无需进行额外配置。以下是 JVM 自动检测支持的常见包管理器、工具和位置列表。
JVM 自动检测知道如何处理:
-
操作系统特定位置:Linux、macOS、Windows
在检测到的所有 JRE/JDK 安装中,将根据工具链优先级规则选择一个。
无论您是使用工具链自动检测还是配置自定义工具链位置,不存在或没有 bin/java 可执行文件的安装都将被忽略并发出警告,但不会生成错误。 |
如何禁用自动检测
为了禁用自动检测,您可以使用 org.gradle.java.installations.auto-detect
Gradle 属性
-
要么使用
-Porg.gradle.java.installations.auto-detect=false
启动 gradle -
或者将
org.gradle.java.installations.auto-detect=false
放入您的gradle.properties
文件中。
自动配置
如果 Gradle 找不到满足构建要求的本地可用工具链,它可以自动下载一个(前提是已配置工具链下载仓库;详情请参阅相关章节)。Gradle 将下载的 JDK 安装到Gradle 用户主目录中。
Gradle 仅下载 GA(通用可用)版本的 JDK。不支持下载早期访问版本。 |
一旦安装在Gradle 用户主目录中,配置的 JDK 就成为自动检测可见的 JDK 之一,并且可以被后续的任何构建使用,就像系统上安装的任何其他 JDK 一样。
由于自动配置只在自动检测未能找到匹配的 JDK 时才启动,因此自动配置只能下载新的 JDK,并且不参与更新任何已安装的 JDK。自动配置的 JDK 即使有更新的次要版本可用,也不会被自动配置再次访问和更新。
工具链下载仓库
通过应用特定的 settings 插件,可以将工具链下载仓库定义添加到构建中。有关编写此类插件的详细信息,请参阅工具链解析器插件页面。
工具链解析器插件的一个例子是基于 foojay Disco API 的 Foojay Toolchains 插件。它甚至还有一个约定变体,只需应用即可自动处理所有必要的配置:
plugins {
id("org.gradle.toolchains.foojay-resolver-convention").version("0.10.0")
}
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0'
}
对于高级或高度特定的配置,应使用自定义工具链解析器插件。
通常,应用工具链解析器插件时,还需要配置它们提供的工具链下载解析器。让我们用一个例子来说明。考虑构建应用的两个工具链解析器插件:
-
其中一个是上面提到的 Foojay 插件,它通过提供的
FoojayToolchainResolver
下载工具链。 -
另一个包含一个名为
MadeUpResolver
的虚构解析器。
以下示例通过 settings 文件中的 toolchainManagement
块在构建中使用这些工具链解析器:
toolchainManagement {
jvm { (1)
javaRepositories {
repository("foojay") { (2)
resolverClass = org.gradle.toolchains.foojay.FoojayToolchainResolver::class.java
}
repository("made_up") { (3)
resolverClass = MadeUpResolver::class.java
credentials {
username = "user"
password = "password"
}
authentication {
create<DigestAuthentication>("digest")
} (4)
}
}
}
}
toolchainManagement {
jvm { (1)
javaRepositories {
repository('foojay') { (2)
resolverClass = org.gradle.toolchains.foojay.FoojayToolchainResolver
}
repository('made_up') { (3)
resolverClass = MadeUpResolver
credentials {
username = "user"
password = "password"
}
authentication {
digest(BasicAuthentication)
} (4)
}
}
}
}
1 | 在 toolchainManagement 块中,jvm 块包含 Java 工具链的配置。 |
2 | javaRepositories 块定义了命名的 Java 工具链仓库配置。使用 resolverClass 属性将这些配置链接到插件。 |
3 | 工具链声明顺序很重要。Gradle 从列表中第一个提供匹配的仓库下载,从列表中的第一个仓库开始。 |
4 | 您可以使用与依赖管理相同的认证和授权选项配置工具链仓库。 |
toolchainManagement 中的 jvm 块仅在应用工具链解析器插件后解析。 |
查看和调试工具链
Gradle 可以显示所有检测到的工具链列表,包括它们的元数据。
例如,要显示项目的所有工具链,请运行:
gradle -q javaToolchains
gradle -q javaToolchains
的输出> gradle -q javaToolchains + Options | Auto-detection: Enabled | Auto-download: Enabled + AdoptOpenJDK 1.8.0_242 | Location: /Users/username/myJavaInstalls/8.0.242.hs-adpt/jre | Language Version: 8 | Vendor: AdoptOpenJDK | Architecture: x86_64 | Is JDK: false | Detected by: Gradle property 'org.gradle.java.installations.paths' + Microsoft JDK 16.0.2+7 | Location: /Users/username/.sdkman/candidates/java/16.0.2.7.1-ms | Language Version: 16 | Vendor: Microsoft | Architecture: aarch64 | Is JDK: true | Detected by: SDKMAN! + OpenJDK 15-ea | Location: /Users/user/customJdks/15.ea.21-open | Language Version: 15 | Vendor: AdoptOpenJDK | Architecture: x86_64 | Is JDK: true | Detected by: environment variable 'JDK16' + Oracle JDK 1.7.0_80 | Location: /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/jre | Language Version: 7 | Vendor: Oracle | Architecture: x86_64 | Is JDK: false | Detected by: MacOS java_home
这有助于调试构建有哪些可用的工具链,它们是如何被检测到的,以及 Gradle 对这些工具链了解哪些元数据。
禁用自动配置
为了禁用自动配置,您可以使用 org.gradle.java.installations.auto-download
Gradle 属性
-
要么使用
-Porg.gradle.java.installations.auto-download=false
启动 gradle -
或者将
org.gradle.java.installations.auto-download=false
放入gradle.properties
文件中。
禁用自动配置后,请确保构建文件中指定的 JRE/JDK 版本已在本地安装。然后,停止 Gradle daemon,以便在下次构建时可以重新初始化。您可以使用 |
移除自动配置的工具链
当需要移除自动配置的工具链时,请移除位于Gradle 用户主目录中 /jdks
目录下的相关工具链。
Gradle Daemon 缓存有关项目的信息,包括工具链路径或版本等配置详情。项目工具链配置的更改可能只有在 Gradle Daemon 重启后才会生效。建议停止 Gradle Daemon,以确保 Gradle 为后续构建更新配置。 |
自定义工具链位置
如果自动检测本地工具链不足或已禁用,还有其他方法可以让 Gradle 知道已安装的工具链。
如果您的设置已经提供了指向已安装 JVM 的环境变量,您也可以让 Gradle 知道需要考虑哪些环境变量。假设环境变量 JDK8
和 JRE17
指向有效的 Java 安装,以下配置指示 Gradle 解析这些环境变量并在查找匹配工具链时考虑这些安装。
org.gradle.java.installations.fromEnv=JDK8,JRE17
此外,您可以使用 org.gradle.java.installations.paths
属性提供一个逗号分隔的路径列表,指向特定的安装目录。例如,在 gradle.properties
中使用以下内容将让 Gradle 知道在检测工具链时要查看哪些目录。Gradle 会将这些目录视为可能的安装目录,但不会深入到任何嵌套目录中。
org.gradle.java.installations.paths=/custom/path/jdk1.8,/shared/jre11
工具链安装优先级
Gradle 将对所有匹配构建工具链规范的 JDK/JRE 安装进行排序,并选择第一个。排序依据以下规则:
-
当前运行 Gradle 的安装优先于任何其他安装
-
JDK 安装优先于 JRE 安装
-
某些供应商优先于其他供应商;它们的排序(从最高优先级到最低优先级)
-
ADOPTIUM
-
ADOPTOPENJDK
-
AMAZON
-
APPLE
-
AZUL
-
BELLSOFT
-
GRAAL_VM
-
HEWLETT_PACKARD
-
IBM
-
JETBRAINS
-
MICROSOFT
-
ORACLE
-
SAP
-
TENCENT
-
其他所有
-
-
主要版本号更高优先于更低的主要版本号
-
次要版本号更高优先于更低的次要版本号
-
安装路径根据其字典顺序具有优先级(用于确定性地决定相同类型、相同供应商和相同版本的安装之间的选择的最后手段标准)
所有这些规则将作为多级排序标准被应用,并遵循所示顺序。让我们用一个例子来说明。一个工具链规范请求使用 Java 17 版本。Gradle 检测到以下匹配的安装:
-
Oracle JRE v17.0.1
-
Oracle JDK v17.0.0
-
Microsoft JDK 17.0.0
-
Microsoft JRE 17.0.1
-
Microsoft JDK 17.0.1
假设 Gradle 运行在一个主要 Java 版本非 17 的环境上。否则,该安装将具有优先权。
当我们应用上述规则对这组安装进行排序时,我们将得到以下排序结果:
-
Microsoft JDK 17.0.1
-
Microsoft JDK 17.0.0
-
Oracle JDK v17.0.0
-
Microsoft JRE v17.0.1
-
Oracle JRE v17.0.1
Gradle 偏好 JDK 而非 JRE,因此 JRE 排在最后。Gradle 偏好 Microsoft 供应商而非 Oracle,因此 Microsoft 安装排在最前面。Gradle 偏好较高的版本号,因此 JDK 17.0.1 排在 JDK 17.0.0 之前。
因此 Gradle 按此顺序选择第一个匹配项:Microsoft JDK 17.0.1。
插件作者的工具链
创建使用工具链的插件或任务时,必须提供合理的默认值并允许用户进行覆盖。
对于 JVM 项目,通常可以安全地假定 java
插件已应用于项目。核心 Groovy 和 Scala 插件以及 Kotlin 插件都会自动应用 java
插件。在这种情况下,将通过 java
扩展定义的工具链用作工具属性的默认值是合适的。这样,用户只需在项目级别配置一次工具链。
以下示例展示了如何将默认工具链用作约定,同时允许用户针对每个任务单独配置工具链。
abstract class CustomTaskUsingToolchains : DefaultTask() {
@get:Nested
abstract val launcher: Property<JavaLauncher> (1)
init {
val toolchain = project.extensions.getByType<JavaPluginExtension>().toolchain (2)
val defaultLauncher = javaToolchainService.launcherFor(toolchain) (3)
launcher.convention(defaultLauncher) (4)
}
@TaskAction
fun showConfiguredToolchain() {
println(launcher.get().executablePath)
println(launcher.get().metadata.installationPath)
}
@get:Inject
protected abstract val javaToolchainService: JavaToolchainService
}
abstract class CustomTaskUsingToolchains extends DefaultTask {
@Nested
abstract Property<JavaLauncher> getLauncher() (1)
CustomTaskUsingToolchains() {
def toolchain = project.extensions.getByType(JavaPluginExtension.class).toolchain (2)
Provider<JavaLauncher> defaultLauncher = getJavaToolchainService().launcherFor(toolchain) (3)
launcher.convention(defaultLauncher) (4)
}
@TaskAction
def showConfiguredToolchain() {
println launcher.get().executablePath
println launcher.get().metadata.installationPath
}
@Inject
protected abstract JavaToolchainService getJavaToolchainService()
}
1 | 我们在任务上声明一个 JavaLauncher 属性。该属性必须标记为 @Nested 输入,以确保任务能响应工具链的变化。 |
2 | 我们从 java 扩展获取工具链规范,用作默认值。 |
3 | 使用 JavaToolchainService ,我们获取一个匹配工具链的 JavaLauncher 提供者。 |
4 | 最后,我们将启动器提供者配置为我们属性的约定。 |
在应用了 java
插件的项目中,我们可以按如下方式使用该任务:
plugins {
java
}
java {
toolchain { (1)
languageVersion = JavaLanguageVersion.of(8)
}
}
tasks.register<CustomTaskUsingToolchains>("showDefaultToolchain") (2)
tasks.register<CustomTaskUsingToolchains>("showCustomToolchain") {
launcher = javaToolchains.launcherFor { (3)
languageVersion = JavaLanguageVersion.of(17)
}
}
plugins {
id 'java'
}
java {
toolchain { (1)
languageVersion = JavaLanguageVersion.of(8)
}
}
tasks.register('showDefaultToolchain', CustomTaskUsingToolchains) (2)
tasks.register('showCustomToolchain', CustomTaskUsingToolchains) {
launcher = javaToolchains.launcherFor { (3)
languageVersion = JavaLanguageVersion.of(17)
}
}
1 | 在 java 扩展上定义的工具链默认用于解析启动器。 |
2 | 没有额外配置的自定义任务将使用默认的 Java 8 工具链。 |
3 | 另一个任务使用 javaToolchains 服务通过选择不同的工具链来覆盖启动器的值。 |
当任务需要访问工具链而未应用 java
插件时,可以直接使用工具链服务。如果向服务提供一个 未配置的 工具链规范,它将始终返回用于运行 Gradle 的工具链的工具提供者。这可以通过在请求工具时传递一个空 lambda 实现:javaToolchainService.launcherFor({})
。
你可以在 编写任务 文档中找到定义自定义任务的更多详细信息。