Native Image

Native Image 是一项将 Java 代码预先编译为二进制文件(即**本机可执行文件**)的技术。本机可执行文件仅包含运行时所需的代码,即应用程序类、标准库类、语言运行时以及来自 JDK 的静态链接本机代码。

Native Image 生成的可执行文件具有以下几个重要优势:

  • 使用的资源仅为 Java 虚拟机所需资源的一小部分,因此运行成本更低
  • 毫秒级启动
  • 立即提供峰值性能,无需预热
  • 可以打包成轻量级容器镜像,实现快速高效部署
  • 提供了更小的攻击面

本机可执行文件由 **Native Image 构建器** 或 native-image 工具创建,该工具处理您的应用程序类和其他元数据,为特定的操作系统和架构创建二进制文件。首先,`native-image` 工具对您的代码执行静态分析,以确定应用程序运行时**可达**的类和方法。其次,它将类、方法和资源编译成二进制文件。整个过程称为**构建时**,以与 Java 源代码到字节码的编译过程明确区分。

`native-image` 工具可用于构建**本机可执行文件**(这是默认选项)或**本机共享库**。本快速入门指南重点介绍如何构建本机可执行文件;要了解有关本机共享库的更多信息,请访问此处

为了熟悉 Native Image 术语并更好地理解该技术,我们建议您阅读Native Image 基础知识

目录 #

先决条件 #

`native-image` 工具位于您的 GraalVM 安装目录的 `bin` 文件夹中,它依赖于本地工具链(C 库头文件、`glibc-devel`、`zlib`、`gcc` 和/或 `libstdc++-static`)。这些依赖项可以使用您机器上的包管理器进行安装(如果尚未安装)。选择您的操作系统以查找满足先决条件的说明。

Linux

在 Oracle Linux 上使用 yum 包管理器

sudo yum install gcc glibc-devel zlib-devel

某些 Linux 发行版可能还需要 libstdc++-static。如果启用了可选存储库(Oracle Linux 7 上的 ol7_optional_latest、Oracle Linux 8 上的 ol8_codeready_builder 以及 Oracle Linux 9 上的 ol9_codeready_builder),则可以安装 libstdc++-static

在 Ubuntu Linux 上使用 apt-get 包管理器

sudo apt-get install build-essential zlib1g-dev

在其他 Linux 发行版上使用 dnf 包管理器

sudo dnf install gcc glibc-devel zlib-devel libstdc++-static

macOS

在 macOS 上使用 xcode

xcode-select --install

Windows

要在 Windows 上使用 Native Image,请安装 Visual Studio 2022 17.6.0 或更高版本,以及 Microsoft Visual C++ (MSVC)。有两种安装选项:

  • 安装带有 Windows 11 SDK(或更高版本)的 Visual Studio Build Tools
  • 安装带有 Windows 11 SDK(或更高版本)的 Visual Studio

Native Image 可以在 PowerShell 或命令提示符中运行,并且只要能够找到合适的 Visual Studio 安装,它就会在 Windows 上自动设置构建环境。

更多信息请参阅在 Windows 上使用 GraalVM 和 Native Image

使用 Maven 或 Gradle 构建本机可执行文件 #

我们为 Native Image 提供了 Maven 和 Gradle 插件,以自动化本机可执行文件的构建、测试和配置。

Maven #

Native Image 的 Maven 插件增加了使用 Apache Maven 将 Java 应用程序编译为本机可执行文件的支持。

  1. 在您喜欢的 IDE 或终端中创建一个名为“helloworld”的新 Maven Java 项目,其结构如下:
     ├── pom.xml
     └── src
         ├── main
         │   └── java
         │       └── com
         │           └── example
         │               └── App.java
    

    例如,您可以运行此命令,使用 quickstart 原型创建一个新的 Maven 项目:

     mvn archetype:generate -DgroupId=com.example -DartifactId=helloworld -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. 将用于将项目编译和组装成可执行 JAR 文件的常规 Maven 插件添加到您的 pom.xml 文件中:
     <build>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.12.1</version>
                 <configuration>
                     <fork>true</fork>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <version>3.3.0</version>
                 <configuration>
                     <archive>
                         <manifest>
                             <mainClass>com.example.App</mainClass>
                             <addClasspath>true</addClasspath>
                         </manifest>
                     </archive>
                 </configuration>
             </plugin>
         </plugins>
     </build>
    
  3. 通过在 pom.xml 中添加以下配置文件来启用 Native Image 的 Maven 插件:
     <profiles>
       <profile>
         <id>native</id>
         <build>
           <plugins>
             <plugin>
               <groupId>org.graalvm.buildtools</groupId>
               <artifactId>native-maven-plugin</artifactId>
               <version>${native.maven.plugin.version}</version>
               <extensions>true</extensions>
               <executions>
                 <execution>
                 <id>build-native</id>
                   <goals>
                     <goal>compile-no-fork</goal>
                   </goals>
                   <phase>package</phase>
                 </execution>
               </executions>
             </plugin>
           </plugins>
         </build>
       </profile>
     </profiles>
    

    version 属性设置为最新的插件版本(例如,通过在 <properties> 元素中指定 <native.maven.plugin.version> 来指定版本)。

  4. 一步编译项目并构建本机可执行文件:
     mvn -Pnative package
    

    名为 helloworld 的本机可执行文件在项目的 target/ 目录中创建。

  5. 运行可执行文件:
     ./target/helloworld 
    

    就是这样,您已成功使用 Maven 为您的 Java 应用程序创建了本机可执行文件。

用于 Native Image 构建的 Maven 插件提供了许多其他功能,对于更复杂的应用程序可能需要这些功能,例如资源自动检测、生成所需配置、在本机可执行文件上运行 JUnit Platform 测试等,详见插件参考文档

Gradle #

Native Image 的 Gradle 插件增加了使用 Gradle 构建工具将 Java 应用程序编译为本机可执行文件的支持。

  1. 在您喜欢的 IDE 或终端中创建一个名为“helloworld”的新 Gradle Java 项目,其结构如下:
     ├── app
     │   ├── build.gradle
     │   └── src
     │       ├── main
     │       │   ├── java
     │       │   │   └── org
     │       │   │       └── example
     │       │   │           └── App.java
     │       │   └── resources
    

    例如,使用 java 插件初始化一个新的 Gradle 项目:

    • 创建一个新目录并进入该目录:
        mkdir helloworld && cd helloworld
      
    • 生成项目:
        gradle init --project-name helloworld --type java-application --test-framework junit-jupiter --dsl groovy
      

      按照提示操作。此命令会设置一个具有必要目录结构和构建文件的新 Java 应用程序。

      如果项目生成器在 gradle.properties 文件中启用了缓存,请注释掉或删除 org.gradle.configuration-cache=true 行。

  2. 通过将以下内容添加到项目的 build.gradle 文件的 plugins 部分中,启用 Native Image 的 Gradle 插件:
     plugins {
     // ...
     id 'org.graalvm.buildtools.native' version 'x.x.x'
     }
    

    'x.x.x' 版本值指定最新的插件版本。

  3. 通过运行 ./gradlew nativeCompile 构建本机可执行文件:
     ./gradlew nativeCompile
    

    名为 app 的本机可执行文件在项目的 app/build/native/nativeCompile/ 目录中创建。

  4. 运行本机可执行文件:
     ./app/build/native/nativeCompile/app 
    

    就是这样,您已成功使用 Gradle 为您的 Java 应用程序创建了本机可执行文件。

用于 Native Image 构建的 Gradle 插件具有许多其他功能,对于更复杂的应用程序可能需要这些功能,例如资源自动检测、生成所需配置、在本机可执行文件上运行 JUnit Platform 测试等,详见插件参考文档

使用 native-image 工具构建本机可执行文件 #

`native-image` 工具将 Java 字节码作为其输入。您可以从类文件、JAR 文件或模块(Java 9 及更高版本)构建本机可执行文件。

从类文件 #

要在当前工作目录中从 Java 类文件构建本机可执行文件,请使用以下命令:

native-image [options] class [imagename] [options]

例如,为 HelloWorld 应用程序构建本机可执行文件。

  1. 将此代码保存到名为 HelloWorld.java 的文件中:
     public class HelloWorld {
         public static void main(String[] args) {
             System.out.println("Hello, Native World!");
         }
     }
    
  2. 编译它并从 Java 类构建本机可执行文件:
     javac HelloWorld.java
     native-image HelloWorld
    

    它将在当前工作目录中创建一个名为 helloworld 的本机可执行文件。

  3. 运行应用程序

     ./helloworld
    

    您可以计时以查看所使用的资源:

     time -f 'Elapsed Time: %e s Max RSS: %M KB' ./helloworld
     # Hello, Native World!
     # Elapsed Time: 0.00 s Max RSS: 7620 KB
    

从 JAR 文件 #

要在当前工作目录中从 JAR 文件构建本机可执行文件,请使用以下命令:

native-image [options] -jar jarfile [imagename]

`native-image` 的默认行为与 `java` 命令对齐,这意味着您可以像通常使用 `java` 命令一样,将 -jar-cp-m 选项传递给 Native Image 进行构建。例如,java -jar App.jar someArgument 会变成 native-image -jar App.jar./App someArgument

请遵循本指南以从 JAR 文件构建本机可执行文件。

从模块 #

您还可以将模块化的 Java 应用程序转换为本机可执行文件。

从 Java 模块构建本机可执行文件的命令是:

native-image [options] --module <module>[/<mainclass>] [options]

有关如何从模块化 Java 应用程序生成本机可执行文件的更多信息,请参阅将 HelloWorld Java 模块构建为本机可执行文件

构建配置 #

您可以向 native-image 工具传递许多选项来配置构建过程。运行 native-image --help 可查看完整列表。传递给 native-image 的选项是从左到右评估的。

有关不同的构建调整和了解更多构建时配置的信息,请参阅Native Image 构建配置

Native Image 在构建过程中将输出进度和各种统计信息。要了解有关输出和不同构建阶段的更多信息,请参阅构建输出。有关本机可执行文件内容的更详细信息,请参阅构建报告

Native Image 和第三方库 #

对于使用外部库的更复杂应用程序,您必须向 native-image 工具提供元数据。

使用 native-image 构建独立二进制文件是在“封闭世界假设”下进行的。`native-image` 工具执行分析以查看应用程序中哪些类、方法和字段是可达的,并且必须包含在本机可执行文件中。此分析是静态的:它不会运行您的应用程序。这意味着应用程序中所有可以在运行时调用的字节码都必须在构建时已知(被观察和分析)。

该分析可以确定某些动态类加载的情况,但它无法总是详尽地预测 Java 本机接口 (JNI)、Java 反射、动态代理对象或类路径资源的所有用法。为了处理 Java 的这些动态特性,您需要向分析提供使用反射、代理等的类,或者要动态加载的类的详细信息。为此,您可以向 `native-image` 工具提供 JSON 格式的配置文件,或者在代码中预先计算元数据。

要了解有关元数据、提供方式以及支持的元数据类型的更多信息,请参阅可达性元数据。要自动为您的应用程序收集元数据,请参阅元数据的自动收集

某些应用程序可能需要额外的配置才能使用 Native Image 进行编译。更多详细信息请参阅Native Image 兼容性指南

Native Image 还可以通过自定义 API 与本机语言互操作。使用此 API,您可以为 Java 应用程序指定自定义本机入口点,并将其构建为本机共享库。要了解更多信息,请参阅与本机代码的互操作性

延伸阅读 #

本入门指南适用于 Native Image 的新用户或经验不足的用户。我们强烈建议这些用户在深入了解之前,查看Native Image 基础知识页面,以便更好地理解一些关键方面。

查看用户指南,以更熟练地使用 Native Image,查找演示示例,并了解潜在的使用场景。

对于循序渐进的学习过程,请查看 Native Image 的构建概述构建配置文档。

考虑运行交互式研讨会以获取一些实践经验:访问Luna Labs 并搜索“Native Image”。

如果您发现了潜在的错误,请在 GitHub 中提交问题

如果您想为 Native Image 贡献力量,请遵循我们的标准贡献工作流程

联系我们