SpringBoot3+graalvm:整合并打包为可执行文件方式
作者:IT利刃出鞘
简介
本文介绍SpringBoot3如何整合graalvm,并打包为可执行文件。Windows和Linux都打包。
版本
- springboot3.3.6
- graalvm21(包含JDK21(21是最新的LTS版本,SpringBoot3最低要求JDK17))
安装graalvm
1.下载
进去后点击下载,即可找到:
下载后得到此文件:graalvm-jdk-21_windows-x64_bin.zip
(JDK21不需要下载native-image了,因为已经捆绑到bin目录了。直接在bin目录下cmd输入native-image即可)
2.安装
将graalvm-jdk-21_windows-x64_bin.zip解压到指定目录,我这里解压到:E:\work\develop_env\graalvm\graalvm-jdk-21_windows-x64_bin
把JDK环境变量配置为GraalVM的路径(因为GraalVM就是JDK)。
由于我要同时用JDK8和JDK21,所以要配置一下,见:Windows使用多个JDK的方法
创建SpringBoot项目
跟原来SpringBoot2的项目结构是一样的。
依赖及代码
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.6</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.knife</groupId> <artifactId>Demo_SpringBoot3</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Demo_SpringBoot3</name> <description>Demo project for Spring Boot3</description> <properties> <java.version>21</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- AOT Graalvm 插件 --> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <!-- <version>3.5.1</version> --> <!-- 指定maven编译的jdk版本。对于JDK8,写成8或者1.8都可以 --> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build> </project>
Controller
package com.knife.example.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @Slf4j @RequestMapping("test") @RestController public class HelloController { @GetMapping("test1") public String test1() { return "success"; } }
启动与测试
启动
Connected to the target VM, address: '127.0.0.1:52251', transport: 'socket'
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v3.3.6)
2024-11-29T15:09:52.849+08:00 INFO 43480 --- [ main] com.knife.example.DemoApplication : Starting DemoApplication using Java 21.0.5 with PID 43480 (E:\project\Idea_Proj\Demo_Java\Demo_SpringBoot3\target\classes started by aaabbb in E:\project\Idea_Proj\Demo_Java\Demo_SpringBoot3)
2024-11-29T15:09:52.852+08:00 INFO 43480 --- [ main] com.knife.example.DemoApplication : No active profile set, falling back to 1 default profile: "default"
2024-11-29T15:09:53.549+08:00 INFO 43480 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2024-11-29T15:09:53.561+08:00 INFO 43480 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-11-29T15:09:53.562+08:00 INFO 43480 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.33]
2024-11-29T15:09:53.612+08:00 INFO 43480 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-11-29T15:09:53.613+08:00 INFO 43480 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 715 ms
2024-11-29T15:09:53.925+08:00 INFO 43480 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2024-11-29T15:09:53.933+08:00 INFO 43480 --- [ main] com.knife.example.DemoApplication : Started DemoApplication in 1.439 seconds (process running for 2.028)
2024-11-29T15:09:56.814+08:00 INFO 43480 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-11-29T15:09:56.814+08:00 INFO 43480 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-11-29T15:09:56.815+08:00 INFO 43480 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
测试接口
访问:http://localhost:8080/test/test1
结果:
打包为可执行文件(Windows的.exe)
从上边来看,好像与SpringBoot2没啥区别。但SpringBoot3有一个重要改动:可以打包为可执行文件,比如:Windows的.exe文件,可以直接执行。性能强、启动快、占内存低。
下边就实战一下打包为可执行文件。
1.下载Visual Studio组件
Windows使用native-image 打包需要C++环境,VisualStudio 可以提供c++开发环境,所以我们要先下载安装好VisualStudio。
必须安装VisualStudio组件,否则在下边mvn -Pnative native:compile时会报错:
Error: Failed to find 'vcvarsall.bat' in a Visual Studio installation.
Please make sure that Visual Studio 2022 version 17.1.0 or later is installed on your system. You can download it at https://visualstudio.microsoft.com/downloads/. If this error persists, please try and run GraalVM Native Image in an x64 Native Tools Command Prompt or file a ticket.
下载
地址:https://visualstudio.microsoft.com/zh-hans/
进去后点击这里:
点击完后,会自动下载VisualStudioSetup.exe
2.安装Visual Studio组件
双击VisualStudioSetup.exe,点击继续,然后到如下界面:
选择正确版本的SDK
运行cmd,输入VER并回车,即可得到版本,找最接近的即可。
选择英文语言包
修改安装位置:
注意:记住这个位置,后边要用。
最后点击安装:
正在安装:
安装完成
如果上边有操作错误,可以点击修改:
删除无用的安装包,之前选定了下载缓存,把它删掉,我的目录是:
D:\ProgramData\Microsoft\VisualStudio\Packages
3.配置环境变量
配置VS环境变量
1.新建VISUAL_STUDIO系统变量
指定到自己的VS路径
2.Path添加VISUAL_STUDIO的bin路径
即:%VISUAL_STUDIO%\VC\Tools\MSVC\14.42.34433\bin\Hostx64\x64
3. 添加INCLUDE环境变量
我上边设置的套件安装位置是:E:\work\develop_env\visual_studio,Windows Kits自动安装到了这里:E:\Windows Kits。为统一管理,我把E:\Windows Kits复制到E:\work\develop_env\visual_studio\下边。
(如果没改过路径,那会在这个路径下:C:\Program Files (x86)\Windows Kits\)
然后添加环境变量:
%VISUAL_STUDIO%\VC\Tools\MSVC\14.42.34433\include;E:\work\develop_env\visual_studio\Windows Kits\10\Include\10.0.19041.0\shared;E:\work\develop_env\visual_studio\Windows Kits\10\Include\10.0.19041.0\ucrt;E:\work\develop_env\visual_studio\Windows Kits\10\Include\10.0.19041.0\um;E:\work\develop_env\visual_studio\Windows Kits\10\Include\10.0.19041.0\winrt
即:
4.添加lib环境变量
与上边INCLUDE类似。
添加lib环境变量,值为:
%VISUAL_STUDIO%\VC\Tools\MSVC\14.42.34433\lib\x64;E:\work\develop_env\visual_studio\Windows Kits\10\Lib\10.0.19041.0\ucrt\x64;E:\work\develop_env\visual_studio\Windows Kits\10\Lib\10.0.19041.0\um\x64
即:
4.打包
打包的步骤如下。
mvn clean mvn compile mvn spring-boot:process-aot mvn -Pnative native:compile
第四步才会生成.jar和.exe文件。
以上四个步骤,可以在Idea里运行(但是必须在上一步配置完环境变量后,重启Idea,否则环境变量不生效!):
结果:
主要步骤
[1/8] Initializing...
[2/8] Performing analysis...
[3/8] Building universe...
[4/8] Parsing methods...
[5/8] Inlining methods...
[6/8] Compiling methods...
[7/8] Layouting methods...
[8/8] Creating image...
看结果文件:
对比一下jar和exe大小:(.exe文件竟然是.jar的四倍)
备注
有人说必须用官方命令行工具,不能用Idea等,其实是因为配置完环境变量后没有重启Idea,导致没编译成功。
官方虽然有说明:
但是,只要重启Idea,就能直接用Idea去通过点击直接操作!
5.运行.exe
直接双击Demo_SpringBoot3.exe即可运行:
测试一下它的接口:(成功访问)
6.对比内存占用
先看上边.exe的内存占用:
把它关掉,运行一下jar看一下
可见,单纯看.exe和.jar的内存占用的话:
- .exe:29MB
- .jar:154MB
打包为可执行文件(Linux)
目标:打包为Ubuntu的可执行文件,本处我的Ubuntu版本:2022.04.04,x86_64架构。
备注:无法在Windows下交叉编译,只能到Linux里直接编译。
1.下载graalvm(Linux版)
进去后点击下载,即可找到:
我的Ubuntu是x86_64,所以下载这个:
下载后得到此文件:graalvm-jdk-21_linux-x64_bin.tar.gz
(JDK21不需要下载native-image了,因为已经捆绑到bin目录了)
2.配置Ubuntu宿主机环境变量
将上边文件上传到Ubuntu宿主机,这里我上传到此路径:/work/env/graalvm/
解压一下:
tar xf graalvm-jdk-21_linux-x64_bin.tar.gz
解压之后:
执行两条命令:
export JAVA_HOME=/work/env/graalvm/graalvm-jdk-21.0.5+9.1 export PATH=$PATH:$JAVA_HOME/bin
执行一下java看看:
3.用Docker搭建maven
4.Maven容器配置环境变量
将graalvm复制到maven容器路径:这里我复制到:/work/env/maven/tool/graalvm/
执行两条命令:
export JAVA_HOME=/tool/graalvm/graalvm-jdk-21.0.5+9.1 export PATH=$PATH:$JAVA_HOME/bin
验证Java版本:java -version
验证native-image:native-image --version
5.Maven容器安装编译工具
apt update apt install build-essential libz-dev zlib1g-dev
native-image要用到二进制编译工具,所以要安装编译工具。
6.Maven容器打包
将项目上传到Linux服务器,然后把它打包为二进制文件。
先把项目打包:tar czf Demo_SpringBoot3.tar.gz Demo_SpringBoot3/
我直接用Windows下的git bash工具:
把Demo_SpringBoot3.tar.gz上传到Linux服务器。
我放到此目录:/work/env/maven/app。将其解压:
tar xf Demo_SpringBoot3.tar.gz
结果:
进入maven容器
docker exec -it maven_3.9 bash
进入/app/Demo_SpringBoot3执行打包命令:
mvn clean mvn compile mvn spring-boot:process-aot mvn -Pnative native:compile
结果(用的虚拟机,运行有点慢,用了十几分钟):
7.运行可执行文件
进入宿主机,进入target目录:/work/env/maven/app/Demo_SpringBoot3/target
执行:./Demo_SpringBoot3
访问: http://192.168.5.193:8080/test/test1
成功!
8.对比内存占用
看二进制执行时的占用:
关掉它,执行一下.jar试试
可见,物理内存占用:
- 二进制:80m
- .jar:169m总结
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。