本页面包含可帮助您将 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 searches for
the JVM using JAVA_HOME 或路径。
生成的二进制文件与系统 库中本地安装的 JVM 兼容,这意味着生成的二进制文件取决于机器上安装的 内容。
如需配置用于执行和测试的 JVM,请使用 --java_runtime_version
标志。默认值为 local_jdk。
封闭测试和编译
如需创建封闭编译,您可以使用命令行标志
--java_runtime_version=remotejdk_11。代码将在从远程代码库下载的 JVM 上进行编译、执行和
测试。如需了解详情,请参阅
Java 运行时版本标志。
配置 Java 中构建工具的编译和执行
还有另一对 JDK 和 JVM 用于构建和执行工具,这些工具在构建过程中使用,但不在构建结果中。该 JDK 和 JVM
使用 --tool_java_language_version 和
--tool_java_runtime_version 进行控制。默认值分别为 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 文件的非递归
globof 。测试应位于
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 文件中的 WORKSPACE 规则添加 Java 执行工具链。添加该规则后,可以使用标志来使用
JVM。如果为同一操作系统和 CPU 架构提供了多个定义,则系统会使用第一个定义。
本地 JVM 的配置示例:
load("@bazel_tools//tools/jdk: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("@bazel_tools//tools/jdk: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 在编译期间使用的多个工具组成,这些工具提供其他功能,例如:Error Prone、严格的 Java 依赖项、标头编译、Android desugaring、覆盖率检测和 IDE 的 genclass 处理。
JavaBuilder 是 Bazel 捆绑的工具,用于执行编译并提供
上述功能。实际编译是使用 JDK 的内部
编译器执行的。用于编译的 JDK 由工具链的 java_runtime
属性指定。
Bazel 会替换一些 JDK 内部组件。如果 JDK 版本 > 9,则使用 JDK 的标志
--patch_module 修补
java.compiler 和 jdk.compiler 模块。如果 JDK 版本为 8,则使用
-Xbootclasspath 标志修补 Java 编译器。
VanillaJavaBuilder 是 JavaBuilder 的第二种实现, 它不会修改 JDK 的内部编译器,也没有任何 其他功能。任何内置 工具链都不会使用 VanillaJavaBuilder。
除了 JavaBuilder 之外,Bazel 在编译期间还会使用其他几个工具。
`ijar` 工具会处理 `jar` 文件,以移除除调用
签名之外的所有内容。生成的 jar 称为标头 jar。它们用于提高
编译增量,方法是仅在函数的正文发生更改时重新编译下游依赖项。
singlejar 工具会将多个 jar 文件打包到一个文件中。
genclass 工具会对 Java 编译的输出进行后处理,并生成
一个 jar,其中仅包含由
注解处理器生成的源代码的类文件。
JacocoRunner 工具会对检测到的文件运行 Jacoco,并以
LCOV 格式输出结果。
TestRunner 工具会在受控环境中执行 JUnit 4 测试。
您可以通过将 default_java_toolchain 宏添加到
a BUILD 文件并注册该宏来重新配置编译,方法是将 register_toolchains 规则添加到
the WORKSPACE 文件或使用
--extra_toolchains 标志。
仅当 source_version 属性与
--java_language_version 标志指定的值匹配时,才会使用该工具链。
工具链配置示例:
load(
"@bazel_tools//tools/jdk: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 = "@bazel_tools//tools/jdk: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 版本 >= 9VANILLA_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 编译器标志配置
您可以使用 package_configuration 的 default_java_toolchain 属性为特定源
文件配置不同的 Java 编译器标志。
请参阅以下示例。
load("@bazel_tools//tools/jdk: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=localjdk_8
build:java11 --java_language_version=11
build:java11 --java_runtime_version=remotejdk_11
这些配置可以与 --config 标志搭配使用,例如
bazel test --config=java11 //:java11_test。