关于 Quarkus 命令模式、基于 UI 的应用程序以及通过 GitHub Actions 进行发布的想法
Quarkus 被宣传为面向微服务的云原生运行时,但命令模式的引入可能开辟了新的、有趣的领域,使其能够获得应用。
在这篇博文中,我将介绍一些关于 Quarkus 命令模式可能用法的想法,这些想法可能对您开发下一个工具时有所帮助。如果您还没有听说过命令模式,我建议您先阅读本介绍,然后再回来。
准备好了吗?好的,我们继续。
通过 GitHub Actions 实现跨平台构建
像 kubectl
这样的命令行工具通常是用 C、Go 或 Rust 等语言编写的,并被编译为适用于各种目标平台的原生可执行文件。这很棒,因为您不需要依赖已安装的 Java;或者担心安装了错误的 Java 版本。
有了 GraalVM 的 native-images,Java 的这个论点不再成立。Quarkus 支持通过 GraalVM 构建原生可执行文件;主要用于为 Linux 容器构建原生版本,但对 OS X 和 Windows 也有实验性支持。将原生构建与命令模式结合使用,听起来是编写命令行工具的非常有吸引力且富有成效的选择。
但是,如何为 Linux、Mac 和 Windows 构建您的原生可执行文件呢?如果您将源代码托管在 GitHub 项目中,我可以告诉您,入门非常简单。GitHub 提供了 Actions,这是一个类似于 Travis CI 的免费服务,但完全集成到 GitHub 体验中。此外,它还为 Linux、Mac 和 Windows 提供运行器(即构建代理)。
要为 Linux 提供原生发行版构建,请在您的仓库中的 .github/workflows
下放置以下文件
name: release-build
on:
release:
types: [created] (1)
jobs:
build:
runs-on: ubuntu-latest (2)
steps:
- uses: actions/checkout@v2
- name: Install graalvm
uses: DeLaGuardo/setup-graalvm@3
with:
graalvm-version: '20.0.0.java11'
- name: Install native-image
run: gu install native-image
- name: Set version
run: ./mvnw versions:set -DnewVersion="${{ github.event.release.tag_name }}" (3)
- name: Build native executable
run: ./mvnw package -Dnative (4)
- name: Upload native executable
id: upload-native-executable
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./target/quarkus-ls-${{ github.event.release.tag_name }}-runner (5)
asset_name: quarkus-ls-${{ github.event.release.tag_name }}-linux
asset_content_type: application/octet-stream
1 | 此构建作业在触发新发行版时触发。如果您是所有者,您将在 releases 下看到“Draft a new release”按钮。 |
2 | 使用 ubuntu 运行器。有关所有支持的环境/运行器的列表,请参阅 GitHub Actions 虚拟环境。 |
3 | 根据指定的发行版版本在 pom.xml 中设置版本 |
4 | 构建原生可执行文件 |
5 | 将构件上传/附加到发行版 |
为 Mac 构建只是提供了另一个带有 runs-on: macos-latest
的作业。
Windows 基本相同,但需要对工具链有更多的关注和了解。让它工作需要一些关于原生构建如何依赖 Visual Studio 的调查。此外,GitHub Actions 上的 Windows 运行器默认的页面文件太小。需要增加它,因为在运行 GraalVM 的 native-image
命令时内存消耗相当高。可以在此处找到适用于 Windows 的原生映像构建的完整示例。
在从 GitHub UI 触发发行版后,所有目标环境的作业都会被触发。所有平台的构件将在几分钟内可用,并可供您的用户使用。构建、托管:100% 免费,无需外部服务或注册。
用于基于 UI 的应用程序的命令模式
命令模式的另一个令人兴奋之处在于,它不仅允许编写漂亮的命令行工具(例如使用 Picocli、Aesh 或 Apache Commons CLI),而且通常允许对应用程序的生命周期进行更多控制。通过嵌入 HTML/JavaScript 前端,我们甚至可以为我们的工具构建 Electron 风格的桌面应用程序,并具有丰富的用户界面。由于 JSF 也很可能被引入 Quarkus,因此在如何构建前端方面有多种选择。
一个非常简单的脚手架不需要太多。如果您有 quarkus-resteasy
作为依赖项,嵌入式服务器将在端口 8080
上启动,就像任何常规 Quarkus 后端应用程序一样。由于您的工具可能在开发人员系统上与其他应用程序服务器或 Quarkus 实例一起运行,因此选择一个不同的端口以避免冲突是一个好主意。
在 application.properties
中配置 quarkus.http.port=0
将使 Quarkus 选择一个随机但可用的端口。如何在应用程序内部知道它是什么端口?通过 @ConfigProperty(name = "quarkus.http.port")
注入配置属性时,您将获得分配的端口。
假设您的前端位于 src/main/resources/META-INF/resources
下(在我的示例中是纯 HTML 和 Javascript),并且使用非常旧的 Java API(Desktop.getDesktop().browse(…)
),您可以通过以下方式启动默认浏览器访问您的应用程序:
import java.awt.Desktop;
import java.net.URI;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;
@QuarkusMain
public class HelloMain implements QuarkusApplication {
@ConfigProperty(name = "quarkus.http.port")
Integer assignedPort; (1)
public static void main(String[] args) {
Quarkus.run(HelloMain.class, args);
}
@Override
public int run(String... args) throws Exception {
URI webappUri = new URI("https://:" + assignedPort + "/index.html"); (2)
Desktop.getDesktop().browse(webappUri);
Quarkus.waitForExit(); (3)
return 0;
}
}
1 | 获取分配的端口 |
2 | 使用默认浏览器打开 Web 应用程序的 index.html 。 |
3 | 不要立即退出,而是等到浏览器/标签页关闭。有关如何执行此操作的选项,请参阅下文。 |
这里还有一些其他考虑因素可以使其可靠地工作。
当浏览器窗口关闭时结束应用程序需要一些反馈。有一些简单的方法可以半可靠地实现这一点(请参阅 index.html 中 unload 的用法,通过调用 一个 REST 端点)。对于桌面类应用程序,可能需要更密切地控制浏览器进程;或者,像 Electron 一样,甚至打包一个自己的 Chrome 版本。
我遇到的一个问题是,在使用我使用的 GraalVM 版本(issue)进行原生模式运行时,Desktop.getDesktop().browse(…)
似乎不一定起作用。如前所述,替代方法是更直接地控制浏览器,例如通过 Runtime.exec(…) 打开一个 Chrome 窗口。有关一些可以尝试的可能性的示例,请参阅入门项目的 main 方法。
总结
看看人们如何使用命令模式会很有趣。也许我们将看到基于 Quarkus 开发的 Electron 风格的桌面应用程序?至少对我来说,这听起来很有前景且富有成效。无需花费时间学习完全不同的堆栈来编写一个小工具。相反,可以使用我从后端开发中熟悉的相同堆栈和 API。
我们已经看到,仅通过 GitHub 和 GitHub Actions 就可以使一个工具易于被人们使用。
如果您对一个我使用了此处提出的想法的更完整的工具感兴趣,请查看我的 bpmn-diff 项目,这是一个 BPMN 文件的 Git difftool。作为额外的好处,它使用 Gradle 而不是 Maven,因此提供了关于 GitHub Actions 用法的额外示例。