SpringBoot3.x原生镜像-Native Image实践
前提
之前曾经写过一篇《SpringBoot3.x 原生镜像-Native Image 尝鲜》,当时SpringBoot
处于3.0.0-M5
版本,功能尚未稳定。这次会基于SpringBoot
当前最新的稳定版本3.1.2
详细分析Native Image
的实践过程。系统或者软件版本清单如下:
组件 | 版本 | 备注 |
---|---|---|
macOS Ventura |
13.4.1(c) |
ARM 架构 |
sdkman |
5.18.2 |
JDK 和各类SDK 包管理工具 |
Liberica Native Image Kit |
23.0.1.r17-nik |
可以构建Native Image 的JDK |
SpringBoot |
3.1.2 |
使用当前(2023-08-20 )最新发布版 |
Maven |
3.9.0 |
- |
安装 sdkman
sdkman是一个轻量级、支持多平台的开源开发工具管理器,可以通过它安装任意主流发行版本(例如OpenJDK
、Kona
、GraalVM
等等)的任意版本的JDK
。通过下面的命令可以轻易安装sdkman
:
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk version
可以通过sdk list java
查看支持的JDK
发行版本:
通过shell
命令sdk install java $Identifier
就可以安装对应的JDK
发行版。例如可以这样安装GraalVM-ce-17
:
sdk install java 17.0.8-graalce
通过shell
命令sdk uninstall java $Identifier
可以卸载对应的JDK
发行版。如果安装了多个版本或者多个发行版的JDK
,可以通过shell
命令sdk default java $Identifier
去指定默认使用的JDK
版本,例如:
sdk default java 17.0.8-graalce
可以通过shell
命令sdk current
或者sdk current java
查看当前正在使用的SDK
或者JDK
版本。
安装 Liberica NIK
Liberica Native Image Kit
是bellsoft
出品的旨在创建高性能原生二进制(Native Binaries
)基于JVM
编写的应用的工具包,简称为Liberica NIK
。Liberica NIK
本质就是把OpenJDK
和多种其他工具包一起封装起来的JDK
发行版,在Native Image
功能应用过程,可以简单把它视为OpenJDK
+ GraalVM
的结合体。可以通过sdk list java
查看相应的JDK
版本:
这里选择JDK-17
的版本进行安装:
sdk install java 23.0.1.r17-nik
# 这里最好把此JDK设置为当前系统的默认JDK,否则后面编译镜像时候会提示找不到GraalVM
sdk default java 23.0.1.r17-nik
安装完成后,通过java -version
验证一下:
编写 SpringBoot 应用
基于Maven
新建一个SpringBoot
应用,这里已经整理好了一份POM
文件,实践过程可以直接用,如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.vlts</groupId>
<artifactId>spring-boot-native-image-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.2</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.version>3.11.0</maven.compiler.version>
<maven.install.version>3.1.1</maven.install.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat.experimental</groupId>
<artifactId>tomcat-embed-programmatic</artifactId>
<version>${tomcat.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>${maven.install.version}</version>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>cn.vlts.NativeImageApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
这里把Maven
的所有插件都提升到当前(2023-08-20
前后)最新版本,原生镜像打包的关键插件是native-maven-plugin
,此插件是跟随spring-boot-starter-parent
进行版本管理,这里无须指定插件的版本。另外,tomcat-embed-programmatic
是一个实验性依赖,可以降低嵌入式Tomcat
的内存使用,在生产中应用时候可以暂不启用此特性。接着编写启动类cn.vlts.NativeImageApplication
:
@SpringBootApplication
@RestController
public class NativeImageApplication {
public static void main(String[] args) {
SpringApplication.run(NativeImageApplication.class, args);
}
@RequestMapping(path = "/")
public ResponseEntity<String> index() {
return ResponseEntity.ok("index");
}
}
构建、测试与发布
三个操作的Maven
命令分别是:
- 构建:
mvn -Pnative native:compile
- 测试:
mvn -PnativeTest test
- 发布:
mvn -Pnative spring-boot:build-image
,注意此命令会打包镜像并且发布到Docker
的官方仓库中
虽然 native:compile 命令表面意义是编译,但是实际上它就是构建原生镜像的命令
执行构建流程:
mvn -Pnative native:compile -Dmaven.test.skip=true
构建结果如下:
其中这个不带.jar
后缀的就是最终的原生镜像,并且Native Image
是不支持跨平台的,它只能在ARM
架构的macOS
中运行(受限于笔者的编译环境)。可以发现它(见上图中的target/spring-boot-native-image-demo
,它是一个二进制执行文件)的体积比executable 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
:
可以看到启动速度达到惊人的毫秒级别,如果应用在生产中应该可以全天候近乎无损发布。当然,理论上Native Image
性能也会大幅度提升,但是限于篇幅这里暂时不进行性能测试。
小结
鉴于SpringBoot3.x
的正式版已经推出一段时间,从文档上看,Native Image
使用的技术已经相对成熟,可以放心用于生产环境。当然,Native Image
目前还存在一些局限性会让一些组件完全无法使用或者部分功能受限(参考Spring Boot with GraalVM),希望这些问题或者局限性有一天能够突破让所有JVM
应用迎来一次性能飞跃。
(本文完 c-2-d e-a-20230820)
SpringBoot3.x原生镜像-Native Image实践的更多相关文章
- SpringBoot3.x原生镜像-Native Image尝鲜
前提 Spring团队致力于为Spring应用程序提供原生映像支持已经有一段时间了.在SpringBoo2.x的Spring Native实验项目中酝酿了3年多之后,随着Spring Framewor ...
- 8.云原生之Docker容器镜像构建最佳实践浅析
转载自:https://www.bilibili.com/read/cv15220861/?from=readlist 本章目录 0x02 Docker 镜像构建最佳实践浅析 1.Dockerfile ...
- 未来已来:云原生 Cloud Native
作者:天知,原文链接 前言 自 2013 年容器(虚拟)技术(Docker)成熟后,后端的架构方式进入快速迭代的阶段,出现了很多新兴概念: 微服务 k8s Serverless IaaS:基础设施服务 ...
- 制作 Python Docker 镜像的最佳实践
概述 ️Reference: 制作容器镜像的最佳实践 这篇文章是关于制作 Python Docker 容器镜像的最佳实践.(2022 年 12 月更新) 最佳实践的目的一方面是为了减小镜像体积,提升 ...
- 微信原生支付 Native扫码支付( V3.3.7 版本)
原文:微信原生支付 Native扫码支付( V3.3.7 版本) [尊重别人的劳动成果,转载请注明出处:一缕晨光工作室,www.wispdawn.com] 前言 辛苦研究三天,遇到各种困难,最终还是克 ...
- 深度解读阿里巴巴云原生镜像分发系统 Dragonfly
Dragonfly 是一个由阿里巴巴开源的云原生镜像分发系统,主要解决以 Kubernetes 为核心的分布式应用编排系统的镜像分发难题.随着企业数字化大潮的席卷,行业应用纷纷朝微服务架构演进,并通过 ...
- 5大最新云原生镜像构建工具全解析,3个来自Google,你了解几个?
1云原生大背景下的镜像构建在分享开始,我想先跟大家简单聊一下云原生,可能不会详细展开,而是带领大家了解一下云原生对镜像构建方面的影响.第一,在接触云原生相关的技术时,无论是要解决开发.测试环境的问题, ...
- 关于OAuth2.0 Authorization Code + PKCE flow在原生客户端(Native App)下集成的一点思考
写在前面 前几天看了园友的一篇文章被广泛使用的OAuth2.0的密码模式已经废了,放弃吧 被再次提起: Implicit Flow Password Grant,均已被标记为Legacy,且OAuth ...
- 精彩分享 | 欢乐游戏 Istio 云原生服务网格三年实践思考
作者 吴连火,腾讯游戏专家开发工程师,负责欢乐游戏大规模分布式服务器架构.有十余年微服务架构经验,擅长分布式系统领域,有丰富的高性能高可用实践经验,目前正带领团队完成云原生技术栈的全面转型. 导语 欢 ...
- react native 入门实践
上周末开始接触react native,版本为0.37,边学边看写了个demo,语法使用es6/7和jsx.准备分享一下这个过程.之前没有native开发和react的使用经验,不对之处烦请指出.希望 ...
随机推荐
- 2020-01-20:mysql中,一张表里有3亿数据,未分表,要求是在这个大表里添加一列数据。数据库不能停,并且还有增删改操作。请问如何操作?
2020-01-20:mysql中,一张表里有3亿数据,未分表,要求是在这个大表里添加一列数据.数据库不能停,并且还有增删改操作.请问如何操作?福哥答案2020-01-20: 陌陌答案:用pt_onl ...
- 2021-03-18:给定一个字符串str,只由‘X’和‘.’两种字符构成。‘X’表示墙,不能放灯,也不需要点亮,‘.’表示居民点,可以放灯,需要点亮。如果灯放在i位置,可以让i-1,i和i+1三个位置被点亮。返回如果点亮str中所有需要点亮的位置,至少需要几盏灯。
2021-03-18:给定一个字符串str,只由'X'和'.'两种字符构成.'X'表示墙,不能放灯,也不需要点亮,'.'表示居民点,可以放灯,需要点亮.如果灯放在i位置,可以让i-1,i和i+1三个位 ...
- Django4全栈进阶之路22 项目实战(三种方式开发部门管理):方式三:FBV+ModelForm+get_object_or_404
1.视图 @login_required def department_list_view(request): departments = Department.objects.all() retur ...
- SPI通信协议
1. SPI 通信协议简介 SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设 备接口,是一种高速全双工的通信总线.它被广泛地使用在 A ...
- 前后端分离架构下使用 Sa-Token 完成登录认证
一.架构分析 目前绝大多数系统都已经采用 "前后端分离" 架构来设计了,传统的Session模式鉴权也不再适合这种架构(或者需要额外写很多的代码来专门适配). Sa-Token 是 ...
- 【Linux】shell编程(一) 变量
[Linux]shell编程(一) 变量 目录 [Linux]shell编程(一) 变量 什么是shell编程 如何运行shell脚本 第一行 #!/bin/bash 第一行叫什么? WHAT IS ...
- SpringBoot开发简单接口流程
SpringBoot开发接口 初始化 新建项目 (1)使用 IDEA 的过程,新建Project,左侧选 Spring Initializr,点Next (2)选 8 版本,点Next (3)左侧选择 ...
- celery笔记三之task和task的调用
本文首发于公众号:Hunter后端 原文链接:celery笔记三之task和task的调用 这一篇笔记介绍 task 和 task 的调用. 以下是本篇笔记目录: 基础的 task 定义方式 日志处理 ...
- 【技术积累】Linux中的基础知识【二】
Linux的发行版本 Linux是一个开源操作系统,有许多发行版,每个发行版都有自己的特点和优势.以下是一些常见的Linux发行版: Ubuntu:Ubuntu是最受欢迎的Linux发行版之一,它拥有 ...
- ndk std_thread 获取pid
本文链接 https://www.cnblogs.com/wanger-sjtu/p/16817532.html 最近在解决tvm绑核问题时,发现android下绑核只有sched_setaffini ...