本頁提供相關資源,協助您將 Bazel 用於 Java 專案。其中包含教學課程、建構規則,以及使用 Bazel 建構 Java 專案的其他相關資訊。
使用 Bazel
下列資源可協助您在 Java 專案中使用 Bazel:
遷移至 Bazel
如果您目前使用 Maven 建構 Java 專案,請按照遷移指南中的步驟,開始使用 Bazel 建構 Maven 專案:
Java 版本
有兩個相關的 Java 版本,並以設定旗標設定:
- 存放區中的原始檔版本
- 用於執行及測試程式碼的 Java 執行階段版本
設定存放區中的原始碼版本
如果沒有額外設定,Bazel 會假設存放區中的所有 Java 原始碼檔案都是以單一 Java 版本編寫。如要指定存放區中來源的版本,請將 build --java_language_version={ver}
新增至 .bazelrc
檔案,其中 {ver}
例如是 11
。Bazel 存放區擁有者應設定這個標記,讓 Bazel 和使用者可以參照原始碼的 Java 版本號碼。詳情請參閱「Java 語言版本標記」。
設定用於執行及測試程式碼的 JVM
Bazel 會使用一個 JDK 進行編譯,另一個 JVM 則用於執行及測試程式碼。
根據預設,Bazel 會使用下載的 JDK 編譯程式碼,並使用本機安裝的 JVM 執行及測試程式碼。Bazel 會使用 JAVA_HOME
或路徑搜尋 JVM。
產生的二進位檔與系統程式庫中本機安裝的 JVM 相容,也就是說,產生的二進位檔取決於機器上安裝的項目。
如要設定用於執行和測試的 JVM,請使用 --java_runtime_version
標記。預設值為 local_jdk
。
密封測試和編譯
如要建立密封編譯作業,可以使用指令列旗標 --java_runtime_version=remotejdk_11
。系統會編譯程式碼,並在從遠端存放區下載的 JVM 上執行及測試。詳情請參閱 Java 執行階段版本標記。
在 Java 中設定建構工具的編譯和執行作業
建構及執行工具時會使用第二組 JDK 和 JVM,這些工具用於建構程序,但不會出現在建構結果中。您可以使用 --tool_java_language_version
和 --tool_java_runtime_version
控制該 JDK 和 JVM。預設值分別為 11
和 remotejdk_11
。
使用本機安裝的 JDK 編譯
Bazel 預設會使用遠端 JDK 編譯,因為這會覆寫 JDK 的內部項目。使用本機安裝的 JDK 設定編譯工具鍊,但不會使用。
如要使用本機安裝的 JDK 進行編譯,也就是使用本機 JDK 的編譯工具鍊,請使用額外旗標 --extra_toolchains=@local_jdk//:all
,但請注意,這可能無法在任意供應商的 JDK 上運作。
詳情請參閱「設定 Java 工具鍊」。
最佳做法
除了一般 Bazel 最佳做法,以下是 Java 專案專屬的最佳做法。
目錄結構
建議採用 Maven 的標準目錄版面配置 (來源位於 src/main/java
下方,測試位於 src/test/java
下方)。
BUILD 檔案
建立 BUILD
檔案時,請遵循下列規範:
每個包含 Java 來源的目錄使用一個
BUILD
檔案,因為這樣可以提升建構效能。每個
BUILD
檔案都應包含一個java_library
規則,如下所示:java_library( name = "directory-name", srcs = glob(["*.java"]), deps = [...], )
程式庫名稱應為包含
BUILD
檔案的目錄名稱。這樣一來,程式庫的標籤就會較短,也就是使用"//package"
而非"//package:package"
。來源應為目錄中所有 Java 檔案的非遞迴
glob
。測試應位於
src/test
下的相符目錄中,並依附於這個程式庫。
為進階 Java 建構作業建立新規則
注意:建立新規則適用於進階建構和測試情境。開始使用 Bazel 時,您不需要這個檔案。
下列模組、設定片段和供應器可協助您建構 Java 專案時擴充 Bazel 的功能:
- 主要 Java 模組:
java_common
- 主要 Java 提供者:
JavaInfo
- 設定片段:
java
其他模組:
設定 Java 工具鍊
Bazel 使用兩種 Java 工具鍊:
- 執行:用於執行及測試 Java 二進位檔,並透過 --java_runtime_version
旗標控制
- 編譯:用於編譯 Java 來源,並透過 --java_language_version
旗標控制
設定其他執行工具鍊
執行工具鍊是 JVM (本機或來自存放區),其中包含版本、作業系統和 CPU 架構的一些額外資訊。
您可以在模組擴充功能中使用 local_java_repository
或 remote_java_repository
存放區規則,新增 Java 執行工具鍊。新增規則後,即可使用旗標提供 JVM。如果為相同的作業系統和 CPU 架構提供多個定義,系統會使用第一個定義。
本機 JVM 的設定範例:
load("@rules_java//toolchains:local_java_repository.bzl", "local_java_repository")
local_java_repository(
name = "additionaljdk", # Can be used with --java_runtime_version=additionaljdk, --java_runtime_version=11 or --java_runtime_version=additionaljdk_11
version = 11, # Optional, if not set it is autodetected
java_home = "/usr/lib/jdk-15/", # Path to directory containing bin/java
)
遠端 JVM 的設定範例如下:
load("@rules_java//toolchains:remote_java_repository.bzl", "remote_java_repository")
remote_java_repository(
name = "openjdk_canary_linux_arm",
prefix = "openjdk_canary", # Can be used with --java_runtime_version=openjdk_canary_11
version = "11", # or --java_runtime_version=11
target_compatible_with = [ # Specifies constraints this JVM is compatible with
"@platforms//cpu:arm",
"@platforms//os:linux",
],
urls = ..., # Other parameters are from http_repository rule.
sha256 = ...,
strip_prefix = ...
)
設定其他編譯工具鍊
編譯工具鍊由 JDK 和 Bazel 在編譯期間使用的多種工具組成,並提供其他功能,例如:容易出錯、嚴格的 Java 依附元件、標頭編譯、Android 脫糖、涵蓋範圍檢測,以及 IDE 的 genclass 處理。
JavaBuilder 是 Bazel 隨附的工具,可執行編譯作業,並提供上述功能。實際編譯作業是由 JDK 透過內部編譯器執行。編譯使用的 JDK 是由工具鍊的 java_runtime
屬性指定。
Bazel 會覆寫部分 JDK 內部項目。如果 JDK 版本大於 9,系統會使用 JDK 的旗標 --patch_module
修補 java.compiler
和 jdk.compiler
模組。如果是 JDK 8 版,Java 編譯器會使用 -Xbootclasspath
標記修補。
VanillaJavaBuilder 是 JavaBuilder 的第二種實作方式,不會修改 JDK 的內部編譯器,也不具備任何額外功能。任何內建工具鍊都不會使用 VanillaJavaBuilder。
除了 JavaBuilder,Bazel 在編譯期間還會使用其他工具。
ijar
工具會處理 jar
檔案,移除所有內容,但呼叫簽章除外。產生的 JAR 稱為標頭 JAR。這類註解只會在函式主體變更時重新編譯下游依附元件,藉此提升編譯增量。
singlejar
工具會將多個 jar
檔案封裝成單一檔案。
genclass
工具會後續處理 Java 編譯的輸出內容,並產生 jar
,其中只包含註解處理器產生的來源類別檔案。
JacocoRunner
工具會對檢測檔案執行 Jacoco,並以 LCOV 格式輸出結果。
TestRunner
工具會在受控環境中執行 JUnit 4 測試。
如要重新設定編譯作業,請將 default_java_toolchain
巨集新增至 BUILD
檔案,然後將其註冊至 MODULE.bazel
檔案 (新增 register_toolchains
規則),或使用 --extra_toolchains
標記。
只有在 source_version
屬性與 --java_language_version
標記指定的值相符時,才會使用工具鍊。
工具鍊設定範例:
load(
"@rules_java//toolchains:default_java_toolchain.bzl",
"default_java_toolchain", "DEFAULT_TOOLCHAIN_CONFIGURATION", "BASE_JDK9_JVM_OPTS", "DEFAULT_JAVACOPTS"
)
default_java_toolchain(
name = "repository_default_toolchain",
configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, # One of predefined configurations
# Other parameters are from java_toolchain rule:
java_runtime = "@rules_java//toolchains:remote_jdk11", # JDK to use for compilation and toolchain's tools execution
jvm_opts = BASE_JDK9_JVM_OPTS + ["--enable_preview"], # Additional JDK options
javacopts = DEFAULT_JAVACOPTS + ["--enable_preview"], # Additional javac options
source_version = "9",
)
可透過 --extra_toolchains=//:repository_default_toolchain_definition
使用,或新增 register_toolchains("//:repository_default_toolchain_definition")
至工作區。
預先定義的設定:
DEFAULT_TOOLCHAIN_CONFIGURATION
:所有功能,支援 JDK 9 以上版本VANILLA_TOOLCHAIN_CONFIGURATION
:沒有其他功能,支援任意供應商的 JDK。PREBUILT_TOOLCHAIN_CONFIGURATION
:與預設值相同,但僅使用預先建構的工具 (ijar
、singlejar
)NONPREBUILT_TOOLCHAIN_CONFIGURATION
:與預設值相同,但所有工具都是從來源建構 (這在 libc 不同的作業系統上可能很有用)
設定 JVM 和 Java 編譯器旗標
您可以透過標記或 default_java_toolchain
屬性設定 JVM 和 javac 標記。
相關標記為 --jvmopt
、--host_jvmopt
、--javacopt
和 --host_javacopt
。
相關的 default_java_toolchain
屬性為 javacopts
、jvm_opts
、javabuilder_jvm_opts
和 turbine_jvm_opts
。
設定套件專用的 Java 編譯器旗標
您可以使用 default_java_toolchain
的 package_configuration
屬性,為特定來源檔案設定不同的 Java 編譯器標記。請參閱下方範例。
load("@rules_java//toolchains:default_java_toolchain.bzl", "default_java_toolchain")
# This is a convenience macro that inherits values from Bazel's default java_toolchain
default_java_toolchain(
name = "toolchain",
package_configuration = [
":error_prone",
],
visibility = ["//visibility:public"],
)
# This associates a set of javac flags with a set of packages
java_package_configuration(
name = "error_prone",
javacopts = [
"-Xep:MissingOverride:ERROR",
],
packages = ["error_prone_packages"],
)
# This is a regular package_group, which is used to specify a set of packages to apply flags to
package_group(
name = "error_prone_packages",
packages = [
"//foo/...",
"-//foo/bar/...", # this is an exclusion
],
)
單一存放區中的多個 Java 原始碼版本
Bazel 僅支援在建構作業中編譯單一版本的 Java 來源。 建構作業。也就是說,建構 Java 測試或應用程式時,所有依附元件都會根據相同的 Java 版本建構。
不過,您可以使用不同的旗標執行個別建構作業。
為方便使用不同標記,特定版本的標記組合可能會與 .bazelrc
設定分組:
build:java8 --java_language_version=8
build:java8 --java_runtime_version=local_jdk_8
build:java11 --java_language_version=11
build:java11 --java_runtime_version=remotejdk_11
這些設定可與 --config
旗標搭配使用,例如 bazel test --config=java11 //:java11_test
。