本页面包含可帮助您将 Bazel 与 Java 项目结合使用的资源。它 指向教程、构建规则和 使用 Bazel 构建 Java 项目
使用 Bazel
以下资源有助于您在 Java 项目中使用 Bazel:
迁移到 Bazel
如果您当前使用 Maven 构建 Java 项目,请按照 迁移指南,了解如何开始使用 Bazel 构建 Maven 项目:
Java 版本
使用配置标志设置了两个相关的 Java 版本:
- 代码库中源文件的版本
- 用于执行代码并测试 它
配置代码库中的源代码版本
如果不进行额外配置,Bazel 会假定
都是以单个 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
。
封闭测试和编译
如需创建封闭编译,您可以使用命令行 flag
--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"
。来源应该是以下内容的非递归
glob
: 目录下的所有 Java 文件。测试应位于
src/test
下的匹配目录中,并依赖于此目录 库。
为高级 Java build 创建新规则
注意:创建新规则适用于高级构建和测试场景。您负责 不需要它。
以下模块、配置 fragment 和提供程序将有助于您 在构建 Java 时扩展 Bazel 的功能 项目:
- 主 Java 模块:
java_common
- 主 Java 提供程序:
JavaInfo
- 配置 fragment:
java
其他模块:
配置 Java 工具链
Bazel 使用两种类型的 Java 工具链:
- 执行,用于执行和测试 Java 二进制文件,通过
--java_runtime_version
标记
- 编译,用于编译 Java 源代码,通过
--java_language_version
旗帜
配置其他执行工具链
执行工具链是本地或存储库中的 JVM,有一些 有关其版本、操作系统和 CPU 的更多信息 架构。
Java 执行工具链可以使用 local_java_repository
或
WORKSPACE
文件中的 remote_java_repository
规则。添加规则会使
使用标记指定可用的 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 使用的多个工具组成 并提供其他功能,例如:错误 容易、严格的 Java 依赖项、头文件编译、Android 脱糖 覆盖率插桩,以及 IDE 的 Genclass 处理。
JavaBuilder 是一款捆绑的 Bazel 工具,用于执行编译,并提供
上述功能。使用内部 API 执行实际编译
由 JDK 指定的编译器。用于编译的 JDK 由 java_runtime
指定
属性。
Bazel 会替换一些 JDK 内部结构。对于 JDK 版本 >9、
使用 JDK 的标志对 java.compiler
和 jdk.compiler
模块进行修补
--patch_module
。对于 JDK 版本 8,使用
-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
文件,然后将 register_toolchains
规则添加到
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
:无其他功能,支持 任意供应商。PREBUILT_TOOLCHAIN_CONFIGURATION
:与默认值相同,但仅使用预构建 工具(ijar
、singlejar
)NONPREBUILT_TOOLCHAIN_CONFIGURATION
:与默认值相同,但所有工具都是 根据源代码构建而成(这可能适用于 libc)
配置 JVM 和 Java 编译器标志
要配置 JVM 和 javac 标志,您可以使用标志或
default_java_toolchain
属性。
相关标志包括 --jvmopt
、--host_jvmopt
、--javacopt
和
--host_javacopt
。
相关的 default_java_toolchain
属性包括 javacopts
、jvm_opts
、
javabuilder_jvm_opts
和 turbine_jvm_opts
。
软件包特定的 Java 编译器标志配置
您可以为特定源代码配置不同的 Java 编译器标志
文件使用 default_java_toolchain
的 package_configuration
属性。
请参考下面的示例。
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 源代码。 build。也就是说,在构建 Java 测试或应用时 是针对相同的 Java 版本构建的。
不过,可以使用不同的标志执行单独的构建。
为了简化使用不同的标志的任务,特定
version 可按 .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
。