构建
本节介绍如何构建 Spring Shell 应用。
Starter 依赖
-
Spring Shell Starter 依赖
名称 | 描述 |
---|---|
spring-shell-starter |
基础 Spring Shell 模块 |
spring-shell-starter-jansi |
使用 JLine jansi 提供者 |
spring-shell-starter-jni |
使用 JLine jni 提供者 |
spring-shell-starter-jna |
使用 JLine jna 提供者 |
spring-shell-starter-ffm |
使用 JLine ffm 提供者 (需要 JDK22+) |
spring-shell-starter-test |
Spring Shell 测试支持 |
终端提供者
与程序运行的底层终端进行交互历来是一个相对复杂的过程,尽管表面看起来一切都只是文本交互。
还记得那些旧式手动打字机或点阵打印机吗?字符在光标所在位置打印,如果需要在不同位置打印,光标就需要移动。简而言之,这就是当前终端模拟器的工作方式。
为了更好地访问和理解现有的终端模拟器环境,JLine 可以通过自己的共享库使用原生代码。JLine 检测哪些提供者存在,然后选择使用其中一个。传统上有三种提供者:`jansi`、`jni` 和 `jna`,它们都应提供相同的功能。
我们的 starter 依赖可以用于专门选择其中的一些 JLine 提供者。
FFM
随着 `JDK22` 的发布,*Foreign Function and Memory API* 从预览版中正式推出,它旨在取代 `JNI`,提供更好、更安全的原生 API。
从 `3.4.x` 版本开始,我们增加了对使用 `JLine` 的 `ffm` 终端提供者编译 Spring Shell 应用的支持。这显然意味着应用需要在 `JDK22+` 环境下运行。新的 JDK 中间版本每 6 个月发布一次,长期支持 (LTS) 版本每 2 年发布一次。在 Spring Shell 能与 Spring Framework 对齐的现有 LTS 版本发布之前,我们将使用最新的 JDK 版本。显然,如果您选择使用 `ffm`,这意味着您可能需要在不方便的时候升级您的 JDK。我们还受限于 JLine 本身用于编译其 `ffm` 部分的 JDK 版本。
FFM 本身在使用某些部分时会导致 JVM 打印警告。这些警告对于终端应用来说显然很烦人,因为它可能会干扰并造成一些混乱。在未来的 JDK 版本中,这些警告也将添加到旧的 JNI 模块中,并且在某个时候,这些警告将变为硬错误。用户将被要求手动启用这些原生“不安全”部分。
在命令行中,为此设置的 JVM 选项是
--enable-native-access=ALL-UNNAMED
如果您有一个 Jar 文件,您可以在其 `META-INF/MANIFEST.MF` 中包含此设置。
Enable-Native-Access: ALL-UNNAMED
可以在构建过程中添加,例如在使用 Gradle 时
tasks.named("bootJar") {
manifest {
attributes 'Enable-Native-Access': 'ALL-UNNAMED'
}
}
至于在 JDK 中启用原生部分,JLine 一直积极主动,已经对此进行了检查,如果原生访问未启用,它将抛出错误。 |
原生支持
将 *Spring Shell* 应用编译为 *GraalVM* 二进制文件的支持主要来自 *Spring Framework* 和 *Spring Boot*,其中此功能称为 *AOT*。AOT (Ahead of Time) 意味着应用上下文在编译时就已准备好,以便进行 *GraalVM* 生成。
在 Spring Framework 和 Spring Boot 的 *AOT* 功能基础上,*Spring Shell* 拥有自己的 *GraalVM* 配置,提供关于二进制文件中应包含哪些内容的提示。通常问题来自尚不包含 *GraalVM* 相关配置或配置不完整的第三方库。
需要使用 *GraalVM Reachability Metadata Repository*,它为第三方库提供了一些缺失的提示。您还需要安装 *GraalVM* 并将 `JAVA_HOME` 指向它。 |
对于 *Gradle*,添加 graalvm 的原生插件并配置元数据仓库。
plugins {
id 'org.graalvm.buildtools.native' version '0.9.16'
}
graalvmNative {
metadataRepository {
enabled = true
}
}
使用 ./gradlew nativeCompile
运行 Gradle 构建时,您应该在 build/native/nativeCompile
目录下获得二进制文件。
对于 Maven
,使用 spring-boot-starter-parent
作为父项目,您将获得一个 native
profile,可用于编译。您需要配置元数据仓库
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<metadataRepository>
<enabled>true</enabled>
</metadataRepository>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
如果您依赖 spring-boot-starter-parent ,它会管理 native-maven-plugin 的版本,并保持最新。 |
使用 ./mvnw native:compile -Pnative
运行 Maven 构建时,您应该在 target
目录下获得二进制文件。
如果一切顺利,可以直接运行此二进制文件,而无需通过 JVM 执行 Boot 应用的 Jar 文件。