编译原生图片

借助 Java 版 Cloud 客户端库,您可以将应用编译为原生映像。这种方法利用预先编译来缩短应用的冷启动时间和内存占用空间,从而提高应用的性能。

客户端库版本

请确保您使用的是 Cloud Libraries 物料清单 (libraries-bom) 的 25.4.0 版或更高版本,或者您使用的是 2022 年 5 月之后发布的客户端库。

大多数用户都使用 libraries-bom 管理客户端库版本。这样可以轻松检查项目中的所有客户端库版本是否相互兼容且为最新版本。

如需详细了解如何在 Maven 和 Gradle 上将 libraries-bom 应用于项目,请参阅更新项目以使用 BOM

受支持的库

支持的 API 表中列出的稳定版 Java 版 Google Cloud 客户端库支持原生映像编译。

准备工作

如需将原生映像编译与所需的 Java 版 Google Cloud 客户端库搭配使用,请按照以下前提步骤操作:

  1. 如果您尚未创建Google Cloud 项目,请创建一个。

  2. 安装 Google Cloud CLI,以便您可以使用项目的凭据运行示例。

  3. 安装 Google Cloud CLI 后,使用以下命令通过应用默认凭据登录:

    gcloud auth application-default login
    
  4. 安装合适的 JDK 发行版,例如 GraalVM

  5. 运行以下命令,确保您已安装原生映像扩展程序:

    gu install native-image
    
  6. 在终端中运行 java -version,验证默认 Java 版本是否已正确设置。 输出类似于以下内容:

    java -version
    openjdk version "17.0.9" 2023-10-17
    OpenJDK Runtime Environment GraalVM CE 17.0.9+9.1 (build 17.0.9+9-jvmci-23.0-b22)
    OpenJDK 64-Bit Server VM GraalVM CE 17.0.9+9.1 (build 17.0.9+9-jvmci-23.0-b22, mixed mode, sharing)
    

将应用构建为原生映像

以下说明使用原生 build 工具插件将应用构建为原生映像。

Maven 设置说明

  1. 将此文本复制并粘贴到应用的 POM 中,以使用原生 Maven 插件为应用构建原生映像。 请务必将 MAIN_CLASS 替换为您的主类的名称,并将 VERSION 替换为原生 Maven 插件的版本,例如 0.10.1

    <profiles>
        <profile>
            <id>native</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <version>VERSION</version>
                        <extensions>true</extensions>
                        <configuration>
                            <mainClass>$MAIN_CLASS</mainClass>
                            <buildArgs>
                                <buildArg>--no-fallback</buildArg>
                                <buildArg>--no-server</buildArg>
                            </buildArgs>
                        </configuration>
                        <executions>
                            <execution>
                                <id>build-native</id>
                                <goals>
                                    <goal>build</goal>
                                </goals>
                                <phase>package</phase>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
    
  2. 运行 mvn package -Pnative 以在 ./target 文件夹中生成原生映像。

  3. 像运行任何可执行文件一样运行应用。例如 ./target/$IMAGE_NAME。插件默认使用项目的制品 ID。

Gradle 设置说明

  1. 通过将以下文本粘贴到 build.gradle 文件中,设置应用的主类。

    application {
        mainClass.set('$MAIN_CLASS')
    }
    
  2. 按照添加插件中的说明添加 native-gradle 插件。

  3. 调用 ./gradlew nativeCompile 以将原生映像构建到 ./build/native/nativeCompile 目录中。

  4. 以可执行文件的形式运行应用。例如 ./build/native/nativeCompile/$PROJECT_NAME。 使用该插件时,映像名称默认为项目名称。

常见问题

SLF4J 兼容性

如果您对具有 SLF4J 依赖项的客户端库执行原生映像编译,则可能会看到以下构建时错误。

Fatal error: com.oracle.graal.pointsto.util.AnalysisError$ParsingError: Error encountered while parsing io.grpc.netty.shaded.io.netty.util.internal.SystemPropertyUtil.getBoolean(java.lang.String, boolean)
Parsing context:
   at io.grpc.netty.shaded.io.netty.util.internal.SystemPropertyUtil.getBoolean(SystemPropertyUtil.java:96)
   at io.grpc.netty.shaded.io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:33)
   at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.AnalysisError.parsingError(AnalysisError.java:153)
...
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of org.slf4j.jul.JDK14LoggerAdapter are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use --trace-object-instantiation=org.slf4j.jul.JDK14LoggerAdapter.

--initialize-at-run-time=io.grpc.netty.shaded.io.netty 添加到 META-INF/native-image/$GROUP_ID/$ARTIFACT_ID/native-image.properties 文件中,以解决此问题。

不过,此配置可能会导致生成的原生映像的性能下降,具体取决于应用遵循的代码路径。

或者,您也可以考虑使用其他日志记录库,例如 Flogger 或 java.util.logging 库。

问题

请通过 GitHub 问题页面报告与 Java 原生映像编译相关的任何问题和疑问。

后续步骤