在 Apple M1 架构上使用 GraalVM 和 Spring Native 构建原生镜像

工程 | Josh Long | 2022 年 3 月 23 日 | ...

它终于发生了!他们做到了!他们及时做到了,我就可以在路上用我闪亮的新笔记本电脑开始构建应用程序了!太棒了!! Oracle 和 GraalVM 团队发布了 GraalVM 和用于 Apple M1 的 GraalVM 原生镜像功能! 我已经等待这一天很久很久了! 我在 2020 年宣布当天就购买了第一台 Apple M1(还有人记得那么久以前吗?从气象学上讲,那是疫情早期)。

Apple 的 M1 设备速度极快,节能,性能远超除了最强大的最新 Intel/NVidia 配置之外的所有配置,同时消耗的功率却远低于其他配置。 简而言之,我是它的忠实粉丝。 但是,迁移到这种新架构并非没有麻烦。

一些 Adobe 应用程序(如 Adobe Premiere 和 Adobe After Effects)、Docker 和 GraalVM 是让我将 M1 机器(我已经从第一台 13 英寸 MacBook Pro 2020 M1 升级到 16 英寸 MacBook Pro 2021 M1 Max 型号)作为我的日常使用的最大障碍。 Docker 已经好多了。 Adobe Premiere 已经好多了,After Effects 也不甘落后(但仍然没有进展)。 而现在,截至昨天,终于,GraalVM 变得更好了。

但是,它尚未 GA,甚至不在出色的 SDKman 项目中。 所以安装它可能很繁琐。 你们还记得手动将东西添加到 PATH 吗? 我记得,我不喜欢! 所以我用谷歌搜索了一下,但一无所获。 然后,就在我不得不工作的时候,我意识到我了不起的朋友和社区传奇人物 Matt Raible (@mraible) 已经弄清楚了。 所以我 ping 了一下他,他给我发了这个 他针对 M1 构建和 Spring Native 提交的 issue,详细说明了他如何让它工作以及如何验证中断。

以下是他的步骤,因为它们适用于我。 注意:我认为他们自 Matt 撰写博客的那天起就发布了更新版本的 GraalVM,因此,我的版本号与他的版本号相差 .1

首先,您需要下载开发者预览版。我正在使用 Java 17 的 22.2.0-dev。所以我选择下载此二进制文件

我把那个.tgz文件放在我的$HOME/Desktop上,然后运行这个脚本来让它安装并可用于SDKMan。这些步骤与 Matt 在他的原始工单中详细说明的步骤相同。

#!/usr/bin/env bash 
BUILD=22.2.0
INSTALLED_PATH=$HOME/.sdkman/candidates/java/${BUILD}.dev.r17-grl
cd $HOME/Desktop/  
rm -rf graalvm-ce-java17-${BUILD}-dev  || echo "no directory to delete."
tar zxpf graalvm-ce-java17-darwin-aarch64-dev.tar.gz 
rm -rf $INSTALLED_PATH || echo "no directory to delete."
mv $HOME/Desktop/graalvm-ce-java17-${BUILD}-dev/Contents/Home $INSTALLED_PATH
sudo xattr -r -d com.apple.quarantine ~/.sdkman/candidates/java/${BUILD}.dev.r17-grl

将所有这些指令放在你的$HOME/Desktop上名为install.sh的文本文件中,然后运行chmod a+x $HOME/Desktop/install.sh使其可执行,然后使用$HOME/Desktop/install.sh运行它。

你需要使这个新安装的版本成为你操作系统的默认版本,所以发出以下命令

BUILD=22.2.0 
sdk default java ${BUILD}.dev.r17-grlz

完成后,你需要在 GraalVM 发行版中使用 gu 实用程序安装 native-image 编译器命令

gu install native-image

打开一个新的 shell 并验证一切正常

➜  java --version 
openjdk 17.0.3 2022-04-19
OpenJDK Runtime Environment GraalVM CE 22.2.0-dev (build 17.0.3+4-jvmci-22.1-b03)
OpenJDK 64-Bit Server VM GraalVM CE 22.2.0-dev (build 17.0.3+4-jvmci-22.1-b03, mixed mode, sharing)

有了这个,你就应该都设置好了。 然后你需要一个应用程序来测试。 所以去我在互联网上第二喜欢的地方,start dot spring dot io,并生成一个 预配置了所有内容的新应用程序。 单击 Generate,然后解压缩并在你选择的 Java IDE 中打开生成的 pom.xml

M1NativeApplication.java 替换为以下内容

package com.example.m1native;

import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.annotation.Id;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

@SpringBootApplication
public class M1nativeApplication {

    public static void main(String[] args) {
        SpringApplication.run(M1nativeApplication.class, args);
    }

    @Bean
    RouterFunction<ServerResponse> routes(CustomerRepository repository) {
        return route()
                .GET("/customers", request -> ok().body(repository.findAll(), Customer.class))
                .build();
    }

    @Bean
    ApplicationRunner runner(CustomerRepository repository) {
        return args -> repository.findAll().subscribe(System.out::println);
    }
}

interface CustomerRepository extends ReactiveCrudRepository<Customer, Integer> {
}

record Customer(@Id Integer id, String name) {
}

添加 src/main/resources/data.sql

insert into customer (name ) values('Josh');
insert into customer (name ) values('Mario');
insert into customer (name ) values('Amey');

添加 src/main/resources/schema.sql

create table if not exists customer
(
    id   serial primary key,
    name varchar(255) not null
);

搞定:你有一个响应式的,非阻塞的 Web 应用程序,与嵌入式,内存中的 SQL 数据库通信。 让我们把这个东西变成一个原生镜像。 在命令行上,运行以下咒语

mvn -Pnative -DskipTests clean package 

这将需要大约 45 秒才能完成。 喝几口咖啡,然后在你的 target/ 目录中运行该应用程序

➜ target/m1native
...
2022-03-23 16:24:15.063  INFO 13901 --- [ ... ] Started M1nativeApplication in 0.036 seconds (JVM running for 0.038)
Customer[id=1, name=Josh]
Customer[id=2, name=Mario]
Customer[id=3, name=Amey]

太棒了!摇滚吧 GraalVM! 这太棒了! 我知道肯定会有错误或问题,但是对于一个开发者预览版来说,它能这么好地工作吗? 太棒了。

现在要弄清楚如何处理我那台吱吱作响且无关紧要的 Intel MacBook Pro...

获取 Spring 新闻通讯

保持与 Spring 新闻通讯的联系

订阅

抢占先机

VMware 提供培训和认证,以加速你的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看所有