Java虽然在市场份额占比巨大,但是在万物云原生下,因它启动时长,资源消耗较大,不易水平扩展等方面都成为了明显的短板,导致市场份额也逐渐减少。而GraalVM弥补了这些缺陷,本文将从实战方向带你打开,原生镜像之路。
1.1 从JDK8->JDK17 你需要知道的
从 JDK 8 升级到 JDK 17 可以让你的应用程序受益于新的功能、性能改进和安全增强。下面是一些 JDK 8 升级到 JDK 17 的最佳实战:
首先,你需要评估你的应用程序是否需要升级到 JDK 17。查看 JDK 17 的新特性、改进和修复的 bug,以确定它们对你的应用程序是否有实际的好处。
详细了解 JDK 8 和 JDK 17 之间的差异是非常重要的。熟悉 JDK 17 中引入的新特性、移除的特性以及可能影响现有代码的变化。
在升级过程中,可能会遇到一些向后不兼容和框架不兼容的变化。例如,一些 API 的使用方式可能发生了变化,或者一些方法已被废弃。在升级之前,你需要对这些变化进行仔细的检查,并相应地修改你的代码。
在升级之前,进行兼容性测试是非常重要的。确保你的应用程序在 JDK 17 下能够正常运行,并且没有出现任何性能下降或功能问题。可以使用自动化测试工具来简化测试过程。
对于大型应用程序或关键系统,建议逐步进行升级。可以先将应用程序迁移到较新的 JDK 版本,如 JDK 11 或 JDK 14,然后再逐步升级到 JDK 17。这样可以降低升级过程中的风险,并使你能够逐步解决遇到的问题。
升级到 JDK 17 后,你可能会注意到一些性能改进。然而,某些代码可能会受到影响并表现出不同的行为。使用性能监控工具来检测潜在的性能问题,并进行必要的调整和优化。
升级 JDK 版本后,你可能还需要更新你的部署和运维流程。例如,JDK 17 中引入了一些新的命令行工具和管理选项。
1.2 为什么要使用jdk17?
1.2.1 长期支持(LTS):
1.2.2 生态系统支持:
1.2.3 新功能和改进:
1.3 强强联合GraalVM
1.3.1 高性能:
1.3.2 AOT 编译:
1.3.3 生态系统支持:
1.3.4 嵌入式支持:
1.3.5 云原生支持:
GraalVM 具有与云原生应用程序开发和部署相关的特性。它可以与 Docker 和 Kubernetes 配合使用,支持快速启动和低内存消耗,适用于云环境中的微服务架构。
2.1 第一步建议先升级依赖项
如果你的项目基于java 8,在升级前最好先升级依赖项,从java 8升级到java 17是一个很大的跨越,依赖项不升级则出问题的概率会比较高,maven可以用mvn versions:display-dependency-updates
命令检查依赖项更新,输出会类似这样:
图1.检查依赖项更新输出示意
或者 jdeps --jdk-internals --multi-release 17 --class-path . encloud-api.jar
dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
图2.迁移前后的参数示意
2.2 环境安装
版本对比、一张官方的对比图
图3.官方的版本对比图示意
java
器使用 GraalVM 默认编译器 Graal 运行 JVM。安装时检查Java版本:$JAVA_HOME/bin/java -version
2.3 二进制的生成
gu install native-image
该native-image工具安装在$JAVA_HOME/bin目录中
2.3.2 maven构建
mvn clean package -Pnative -Dmaven.test.skip=true
2.4 出现的坑点
报错如下:
图4、5.报错示意
2.4.3 对于java 应用来说 打出来的二进制可能出现乱码 因此需要强制指定
图6.强制指定示意
2.5 模块化 初体验
git clone https://github.com/graalvm/graalvm-demos
cd graalvm-demos/native-hello-module
结构图
├── hello
│ └── Main.java
│ > package hello;
│ >
│ > public class Main {
│ > public static void main(String[] args) {
│ > System.out.println("Hello from Java Module: "
│ > + Main.class.getModule().getName());
│ > }
│ > }
│
└── module-info.java
> module HelloModule {
> exports hello;
> }
mvn package
$JAVA_HOME/bin/java --module-path target/HelloModule-1.0-SNAPSHOT.jar --module HelloModule
$JAVA_HOME/bin/native-image --module-path target/HelloModule-1.0-SNAPSHOT.jar --module HelloModule
./hellomodule
2.6 编译器操作模式
Graal 作为 HotSpot JIT 编译器有两种运行模式:
libgraal:Graal 编译器提前编译到本地共享库中。在这种运行模式下,共享库由 HotSpot VM 加载。编译器使用与 HotSpot 堆分开的内存,并且从一开始就运行得很快,因为它不需要预热。这是默认和推荐的操作模式。
jargraal:Graal 编译器经历与 Java 应用程序的其余部分相同的预热阶段。也就是说,在编译其热方法之前首先对其进行解释。-XX:-UseJVMCINativeLibrary使用命令行选项选择此模式。这将延迟达到最佳性能的时间。
2.7 本机映像构建配置
maven常用配置
<buildArgs>
如果要将其他参数传递给本机图像生成器,请<buildArgs> 在插件的配置中使用
<buildArgs>
<arg>--argument</arg>
</buildArgs>
<skipNativeBuild>
要跳过本机图像的生成,请在插件的配置中提供以下内容:
<skipNativeBuild>true</skipNativeBuild>
<skipNativeTests>
要跳过本机图像编译测试的生成和执行,请在插件的配置中提供以下内容:
<skipNativeTests>true</skipNativeTests>
<debug>
如果要启用调试信息的生成,请在插件配置中提供以下内容:
<debug>true</debug>
<useArgFile>
如果要使用参数文件构建原生图像,请在插件配置中提供以下内容:
<useArgFile>true</useArgFile>
2.8 日志记录添加到本机可执行文件
{
"name" : "java.util.logging.FileHandler",
"methods" : [
{ "name" : "<init>", "parameterTypes" : [] },
]
}
3、将以下 Java 代码保存到名为LoggerRunTimeInit.java的文件中,然后使用以下命令对其进行编译javac
:
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class LoggerTest {
public static void main(String[] args) throws IOException {
LogManager.getLogManager().readConfiguration(LoggerRunTimeInit.class.getResourceAsStream("/logging.properties"));
Logger logger = Logger.getLogger(LoggerRunTimeInit.class.getName());
logger.log(Level.WARNING");
}
}
4、下载 logging.properties 资源文件 (https://www.graalvm.org/docs/reference-manual/native-image/assets/logging.properties) 并将其保存在与 LoggerRunTimeInit.java 相同的目录中。
5、构建并运行本机可执行文件:
native-image LoggerTest -H:IncludeResources="logging.properties"
./LoggerTest
6、它应该产生类似于以下内容的输出:
WARNING
2.9 使用jdk17和graalvm 你可以体验到
启动时间:GraalVM 提供了 Just-In-Time (JIT) 编译和 Ahead-Of-Time (AOT) 编译的能力。AOT 编译可以将 Java 应用程序编译成本地机器码,从而加快应用程序的启动时间。相比之下,传统的 JIT 编译需要一些启动时间来进行动态编译。因此,使用 GraalVM 的 AOT 编译可能会显著减少启动时间,提高应用程序的响应性能。
内存占用:GraalVM 的 AOT 编译可以减少应用程序的内存占用,因为本地机器码通常比解释执行的字节码更加紧凑。这可以提高应用程序的可扩展性和资源利用率。
即时编译性能:GraalVM 的 JIT 编译器在某些情况下可能会提供更好的性能。它可以对热点代码进行更优化的编译,以提高执行速度。这可能在一些计算密集型任务或高并发场景中带来性能提升。
应用本身大小:在真实环境下占用对比,且二进制版本是已经整合5个项目的完整项目,而jar只是其中1/5。
图7.应用本身大小对比示意
2.10 demo开箱即体验
在云原生下,Java升级到最新版本并使用GraalVM可以提高Java应用的性能、体验新特性、提高资源利用率和适应万物云原生的能力。
求分享
求点赞
求在看