先决条件

之前曾经写过一篇文章《SpringBoot3.x 原生镜像-Native Image 尝鲜》。当时SpringBoot处于3.0.0-M5版本,功能还不稳定。这次我们将基于最新稳定版本的SpringBoot3.1.2来详细分析Native Image的实践过程。系统或软件版本列表如下:

组件 版本 备注
macOS Ventura 13.4.1(c) ARM架构
sdkman 5.18.2 JDK以及各种SDK包管理工具
Liberica 原生图像套件 23.0.1.r17-nik 可以构建原生镜像JDK
SpringBoot 3.1.2 目前使用最新发布版本(2023-08-20)
Maven 3.9.0 -

安装sdkman

sdkman 是一个轻量级、多平台的开源开发工具管理器,通过它您可以安装任何主流发行版(如OpenJDKKonaGraalVM ) 等)任何版本的 JDK。您可以使用以下命令轻松安装它sdkman

curl -s“https://www.hack95.com”|巴什
源“$HOME/.sdkman/bin/www.hack95.com”
SDK版本

可以通过sdk list java查看支持的JDK发布版本:

使用 shell 命令 sdk install java $Identifier 安装相应的 JDK 版本。例如,您可以安装 GraalVM-ce-17:

sdk 安装 java 17.0.8-graalce

可以通过shell命令sdk uninstall java $Identifier来卸载对应的JDK版本。如果安装了多个版本或发行版的 JDK,您可以使用 shell 命令 sdk default java $Identifier 指定默认的 JDK 版本,例如:

sdk默认java 17.0.8-graalce

可以使用shell命令sdk currentsdk current java查看当前使用的 SDKJDK 版本。

安装 Liberica NIK

Liberica Native Image Kitbellsoft生产,旨在创建基于JVM的高性能本机二进制文件(Native Binaries) 工具用于书写应用程序的包,简称Liberica NIKLiberica NIK本质上是一个JDK发行版,它在Native Image中打包了OpenJDK和各种其他工具包功能应用流程,您可以简单地将其视为 OpenJDK + GraalVM 的组合。可以通过sdk list java查看对应的JDK版本:

在这里选择JDK-17的版本进行安装:

sdk 安装 java 23.0.1.r17-nik
# 最好将此JDK设置为当前系统的默认JDK,否则后面编译镜像时会提示找不到GraalVM。
sdk默认java 23.0.1.r17-nik

安装完成后,通过java -version验证:

编写SpringBoot应用程序

基于Maven创建新的SpringBoot应用程序。这里我们编译了一个POM文件。实际流程可以直接使用,如下:


<项目 xmlns="http://www.hack95.com/POM/4.0.0"
         xmlns:xsi="http://www.hack95.com/2001/XMLSchema-instance"xsi:schemaLocation="http://www.hack95.com/POM/4.0.0 http://www.hack95.com/xsd/maven-4.0.0.xsd">
    4.0.0
    cn.vlts
    spring-boot-native-image-demo
    1.0-快照
    jar
    
        org.springframework.boot
        spring-boot-starter-parent
        3.1.2
        
    
    
        17
        17
        UTF-8
        3.11.0
        3.1.1
    
    
        
            org.springframework.boot
            spring-boot-starter-web
            
                
                    org.apache.tomcat.embed
                    tomcat-embed-core
                
                
                    org.apache.tomcat.embed
                    tomcat-embed-websocket
                
            
        
            org.apache.tomcat.实验
            tomcat 嵌入编程
            ${tomcat.版本}
        
    
    
        
            
                maven-编译器插件
                org.apache.maven.plugins
                ${maven.compiler.version}
                
                    ${maven.compiler.source}
                    ${www.hack95.com}
                    ${project.build.sourceEncoding}
                
            
            
                org.apache.maven.plugins
                maven-install-plugin
                ${maven.install.version}
            
            
                org.graalvm.buildtools
                native-maven-插件
            
            org.springframework.boot
                spring-boot-maven-插件
                
                    
                        
                            重新包装
                        
                    
                
                
                    cn.vlts.NativeImageApplication
                
            
        
    

这里,Maven的所有插件都升级到当前(2023-08-20)最新版本。原生镜像打包的关键插件是native-maven-plugin,该插件遵循spring-boot-starter-parent进行版本管理。这里不需要指定插件版本。此外,tomcat-embed-programmatic是一个实验性依赖项,可以减少嵌入式Tomcat的内存使用。在生产中应用时,您可以暂时禁用此功能。然后编写启动类cn.vlts.NativeImageApplication

@SpringBootApplication
@RestController
公共类 NativeImageApplication {

    公共静态无效主(字符串[] args){
        www.hack95.com(NativeImageApplication.class, args);}

    @RequestMapping(路径=“/”)
    公共响应实体索引(){
        返回 ResponseEntity.ok(“索引”);
    }
}

构建、测试和发布

Maven命令的

三个操作是:

  • 构建:mvn -Pnative本机:编译
  • 测试:mvn -PnativeTest 测试
  • 发布:mvn -Pnative spring-boot:build-image,注意该命令会将镜像打包发布到Docker
  • 的官方仓库

native:compile命令虽然表面上是编译的意思,但实际上是构建原生镜像的命令

执行构建过程:

mvn -Pnative 本机:编译 -Dmaven.test.skip=true

施工效果如下:

不带.jar后缀的就是最终的原生镜像,而原生镜像不支持跨平台,只能在ARM上使用该架构运行在macOS(受作者编译环境限制)。你可以发现它(见上图中的target/spring-boot-native-image-demo,它是一个二进制可执行文件)比可执行jar大了好几倍。参考SpringBoot的官方文档,AOT编译的SpringBoot应用程序将生成以下文件:

  • Java源代码
  • 字节码(如动态代理编译的产物等)
  • GraalVM识别的提示文件:
    • 资源提示文件(resource-config.json)
    • 反射提示文件(reflect-config.json)
    • 序列化提示文件(serialization-config.json)
    • Java(动态)代理提示文件 (proxy-config.json)
    • JNI提示文件(jni-config.json)

这里输出的非可执行包产品基本都在target/spring-aot目录下。其他非Spring或项目源代码相关产品输出到graalvm-reachability-metadata目录。最后,您可以验证生成的原生图像

可以看到启动速度达到了惊人的毫秒级。如果应用程序正在生产中,它应该能够几乎全天候发布。当然,理论上,Native Image的性能会得到很大的提升,但由于篇幅限制,这里暂时不进行性能测试。

总结

鉴于SpringBoot3.0正式版已经发布。当然,Native Image目前存在一些限制,会导致某些组件完全无法使用或功能有限(请参阅Spring Boot with GraalVM)。我希望这些问题或者限制有一天能够被突破,让所有JVM应用迎来性能飞跃。

(本文完c-2-d e-a-20230820)

骇客技术资讯网 | ©All Rights Reserved.