首页 > Java > java教程 > JBang,Java 生态系统中缺失的脚本工具

JBang,Java 生态系统中缺失的脚本工具

Patricia Arquette
发布: 2025-01-05 04:01:39
原创
196 人浏览过

Java生态已经有两个强大的项目管理工具,Maven和Gradle,但缺少一个简单而强大的脚本工具。
这就是 JBang 发挥作用的地方。
它是一个简约但功能强大的 Java、Kotlin 和 Groovy 文件启动器。
事实上,它允许您像运行脚本一样轻松地运行代码。
它还提供许多其他功能,例如依赖管理、模板和 App Store。
让我们在这篇文章中探索 JBang 及其功能。

设置

jbang 命令行可以使用不同的方法安装在 Windows、Linux 和 macOS 上,这些方法在此处有详细记录。
我们可以通过运行 jbang --version 来验证安装。

除此之外,最好为我们最喜​​欢的 IDE 安装随附的 IDE 扩展。
此处列出了支持的 IDE 扩展。

JBang 不依赖于 JDK 到 JRE,但运行使用 Java 的脚本需要 JDK。
您可以通过运行 jbang jdk install 23 来安装 JBang,这将安装 JDK 23。

我们现在准备编写我们的第一个脚本。

第一个脚本

让我们创建一个简单的脚本来打印“Hello, World!”到控制台。

> jbang init helloworld.java
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

这将创建一个名为 helloworld.java 的文件,可以使用 jbang helloworld.java 运行。

> jbang helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

当您打开该文件时,您将看到它是一个普通的 Java 文件,带有 main 方法和特定的第一行。

///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }

正如我们将看到的,JBang 脚本由三部分组成:shebang、可选属性和脚本本身。
我们将在接下来的部分中使用第二部分的一些属性,但让我们重点关注第一部分。

这部分 ///usr/bin/env jbang "$0" "$@" ;退出$?告诉系统使用 JBang 来运行脚本。
它在 Unix 生态系统中被称为 shebang,用于指定脚本的解释器。
我们可以在 Unix 系统(macOS、Linux)上通过运行 chmod x helloworld.java 使脚本可执行,然后运行 ​​./helloworld.java 来说明这一点。

/// usr/bin/env jbang "<pre class="brush:php;toolbar:false">///usr/bin/env jbang "<pre class="brush:php;toolbar:false">//JAVA 23+
//COMPILE_OPTIONS --enable-preview -source 23
//RUNTIME_OPTIONS --enable-preview
登录后复制
登录后复制
登录后复制
" "$@" ; exit $? //JAVA 23+ //COMPILE_OPTIONS --enable-preview -source 23 //RUNTIME_OPTIONS --enable-preview void main(String... args) { System.out.println("Hello World"); } " "$@" ; exit $? //JAVA 25 //COMPILE_OPTIONS --enable-preview -source 25 //RUNTIME_OPTIONS --enable-preview import java.util.concurrent.Callable; import java.util.concurrent.StructuredTaskScope; import static java.lang.System.*; void main(String... args) { out.println("Hello Java 25"); Callable task1 = () -> { out.println("Task 1" + Thread.currentThread()); return "Task 1"; }; Callable task2 = () -> { out.println("Task 2" + Thread.currentThread()); return 2; }; try ( var scope = new StructuredTaskScope()) { StructuredTaskScope.Subtask subtask1 = scope.fork(task1); StructuredTaskScope.Subtask subtask2 = scope.fork(task2); scope.join(); } catch (Exception e) { e.printStackTrace(); } }

我们现在可以像使用任何 Java 文件一样开发脚本。
一旦准备好发布,我们可以将其导出为不同的格式,如下所示:

  • 一个jar文件:jbang导出可移植的helloworld.java。如果您的脚本使用依赖项,则更推荐使用以下命令。
  • A fatjar:包含所有依赖项:jbang export fatjar helloworld.java。该方法仍然需要在目标机器上安装JDK/JRE。如果您不想这样做,更推荐使用接下来的命令。
  • 包含 JDK 的 jlink 二进制文件:jbang export jlink helloworld.java。要运行的二进制文件是 Unix 上的 helloworld-jlink/bin/helloworld 或 Windows 上的 helloworld-jlink/bin/helloworld.bat。
  • A 原生 imgae:jbang 导出原生 helloworld.java。这需要安装 GraalVM。

脚本也可以导出为 mavenrepo: jbang export mavenrepo helloworld.java

JDK管理

如前一章所示,JBang 可以在您的计算机上安装 JDK。
您可以使用 jbang jdk list 列出已安装的 JDK,使用 jbang jdk list --available --show-details 列出可安装的 JDK,使用 jbang jdk install [version] 安装新的 JDK。 Jbang 还支持使用 SDKMAN 来管理受支持系统上的 JDK。

此外,可以在脚本中指定 JDK 版本。
这是通过将以下行添加到脚本属性来完成的: //JAVA [version](如果我们想要精确版本)或 //JAVA [version](如果我们至少想要一个特定版本)。
在这种情况下,JBang 将自动安装所需的 JDK 版本并仅将其用于该脚本,而不更改系统的默认 JDK。

例如,以下脚本使用 Java 25 和一些预览功能。

> jbang init helloworld.java
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

没有“Main”类的脚本

由于脚本往往是轻量级的,因此最好在没有类和 main 方法的情况下编写它们。
幸运的是,Java 有一个称为隐式声明类和实例主方法的功能(在 Java 23 中仍处于预览状态)。
此功能允许在没有类和静态 main 方法的情况下编写 java 程序和 JBang 脚本。

下面的脚本将被编译并执行,没有任何问题。

> jbang helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

这是通过向脚本添加以下属性来实现的。

///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }

第一行 //JAVA 23 告诉 JBang 使用 Java 23 或更高版本。
第二行和第三行 //COMPILE_OPTIONS --enable-preview -source 23 和 //RUNTIME_OPTIONS --enable-preview 分别启用编译和运行时的预览功能。

一旦功能变得稳定,我们可以删除这 3 行,脚本仍然可以工作。整齐!

依赖关系

JBang 支持以 Gradle 样式依赖项的形式向脚本添加依赖项,方法是为每个依赖项添加 //DEPS atrefact-id:atrefact-name:version 行。
例如,要使用 jfiglet 库,我们可以将以下行添加到脚本中: //DEPS com.github.lalyos:jfiglet:0.0.8.

> jbang init helloworld.java
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

目录

JBang 中的目录允许有效地组织和共享脚本和模板。
此功能对于想要共享常见任务或工作流程的脚本集合的团队或社区特别有用。
对于想要分发入门代码或在不提供源代码的情况下显示练习结果的教师来说,它也很有用。

目录是一个名为 jbang-catalog.json 的 JSON 文件,其中包含两组项目:别名和模板。
别名允许使用简单的命令从目录运行脚本,而模板则提供新脚本的起点。
目录可以是远程的或本地的,并且可以根据需要添加和使用任意数量的本地或远程存储库。
有趣的是,JBang 在设置过程中创建了一个本地目录,其中包含一些开箱即用的别名和模板。

JBang 按以下顺序在这些目录中查找本地目录(源 JBang 文档):

  1. 当前目录,./jbang-catalog.json
  2. 在./.jbang/jbang-catalog.json中
  3. 在父目录中,../jbang-catalog.json
  4. 在父级的 .jbang 目录中,../.jbang/jbang-catalog.json
  5. 并向上递归重复步骤3和4到文件系统的根
  6. 最后一步它将查看 $HOME/.jbang/jbang-catalog.json

JBang 将在许多开源存储库(如 GitHub、GitLab、Bitbucket 等)中查找远程目录。
我将在本文中使用 GitHub 作为示例。
要创建远程目录,您需要将 jbang-catalog.json 添加到存储库的根文件夹中。
然后通过 account/repository_name 引用该目录。
如果您的存储库名为 jbang-catalog,那么您可以通过帐户引用它。
因此,例如,如果我的 GitHub 帐户名为 yostane,并且我有一个名为 curs-java 的存储库,其中包含一个名为 jbang-catalog.json 的文件的目录,我可以通过 yostane/cours-java 引用该目录。此外,如果我在名为 jbang-catalog 的存储库中有一个 jbang-catalog.json,那么我可以通过 yostane/jbang-catalog 或简单地 yostane 引用它。

> jbang helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

以下章节将展示如何使用目录中的别名和模板。

别名

JBang 中的别名允许从目录运行脚本。
完整语法是 jbang alias@account/repository [args] 和 jbang alias [args] 分别表示远程和本地别名。

可以使用以下格式在目录文件的别名部分定义别名:

> jbang init helloworld.java
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

这是我在 DevoxxMA 2024 会议期间使用的目录。

> jbang helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

您可以使用以下命令运行这些别名:

  • jbang palcli@yostane/cours-java 女士
  • jbang palqrest@yostane/cours-java
  • jbang hellojfx@yostane/cours-java

官方JBang GitHub帐户提供了包含许多别名和模板的目录。
让我们运行其中的一些:

  • jbang httpd@jbangdev 运行本地网络服务器。
  • jbang gavsearch@jbangdev [arg] 在 search.maven.org 上搜索 [arg]。

模板

模板,这是预定义的脚本,可以用作新脚本的起点。
它们使用以下格式在目录文件的模板部分中定义:

///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }

使用模板时,JBang 会在 file-refs 属性中创建所有文件的副本。
当 file-ref 包含 {basename} 时,JBang 会将其替换为正在创建的脚本的名称。
当文件引用使用 .qute 扩展名时,JBang 使用 Qute 模板引擎

以下是一些现成可用的模板的示例:

  • 使用 picocli 的 CLI 脚本:jbang init -t cli hellocli.java
  • Quarkus 单文件 REST API:jbang init -t qrest helloqrest.java

我们还可以使用社区共享的互联网模板。
例如,此命令创建一个 JUnit 单元测试文件: jbang init -t junit@jbangdev file_to_test.java.
从命令中我们可以找到 jbangdev/jbang-catalog 存储库中定义模板的 jbang-catalog.json。

/// usr/bin/env jbang "<pre class="brush:php;toolbar:false">///usr/bin/env jbang "<pre class="brush:php;toolbar:false">//JAVA 23+
//COMPILE_OPTIONS --enable-preview -source 23
//RUNTIME_OPTIONS --enable-preview
登录后复制
登录后复制
登录后复制
" "$@" ; exit $? //JAVA 23+ //COMPILE_OPTIONS --enable-preview -source 23 //RUNTIME_OPTIONS --enable-preview void main(String... args) { System.out.println("Hello World"); } " "$@" ; exit $? //JAVA 25 //COMPILE_OPTIONS --enable-preview -source 25 //RUNTIME_OPTIONS --enable-preview import java.util.concurrent.Callable; import java.util.concurrent.StructuredTaskScope; import static java.lang.System.*; void main(String... args) { out.println("Hello Java 25"); Callable task1 = () -> { out.println("Task 1" + Thread.currentThread()); return "Task 1"; }; Callable task2 = () -> { out.println("Task 2" + Thread.currentThread()); return 2; }; try ( var scope = new StructuredTaskScope()) { StructuredTaskScope.Subtask subtask1 = scope.fork(task1); StructuredTaskScope.Subtask subtask2 = scope.fork(task2); scope.join(); } catch (Exception e) { e.printStackTrace(); } }

应用商店

JBang App Store 是一个 Web 应用程序,允许浏览索引目录的别名。
它提供了一种发现和使用各种工具和实用程序的便捷方法,无需复杂的设置或安装过程。
例如,当我们搜索 yostane 时,我们应该能够找到我在不同目录中定义的不同别名。
下图显示了搜索结果。

JBang, the missing scripting tool of the Java ecosystem

以下是我在App Store浏览时发现的一些有趣又好笑的脚本:

  • 考赛。以下是运行脚本的一些示例:
    • jbangowsay@ricksbrown/cowsay MOO!
    • jbangowsay@ricksbrown/cowsay -f Dragon“我是维尔德拉·暴风雨!”
  • 查找类似 grep 的子字符串: jbang grep@a-services "hello" 。
  • 从图像创建 PDF:images2pdf@a-services。以下命令将从两个图像创建 PDF 文件:
///usr/bin/env jbang "<pre class="brush:php;toolbar:false">  {
    "catalogs": {},
    "aliases": {
      // aliases
    },
    "templates": {
      // templates
    }
  }
登录后复制
" "$@" ; exit $? //DEPS com.github.lalyos:jfiglet:0.0.9 import com.github.lalyos.jfiglet.FigletFont; public class DependenciesDemo { public static void main(String... args) throws Exception { System.out.println(FigletFont.convertOneLine("JBang is amazing")); } }

当您发布目录时,它很可能会在 JBang AppStore 下次索引后出现。
这是此处定义的预定 GitHub 操作。

一些具有著名框架的示例

通过 JBang,我们可以创建使用流行框架和库的单文件应用程序。
一些示例包括 Quarkus、picolcli 和 JavaFX。
让我们在以下部分中探讨一些示例。

JavaFX(openjfx)

JavaFX 是一个桌面和 UI 框架。
其官方网站是 openjfx.io,也受到 Gluon 的支持,Gluon 提供了额外的 UI 组件,并为 JavaFX 带来了移动应用程序支持。
JBang 支持此框架,可用于创建单文件 JavaFX 应用程序。

以下是使用 JBang 创建的一些 JavaFX 应用程序示例:

  • 基本窗口
  • 更漂亮的例子jbang https://gist.github.com/FDelporte/c69a02c57acc892b4c996a9779d4f830
  • 模板 jbang init -t javafx@yostane hellojfx

夸库斯

Quarkus 是一个针对 Kubernetes 和无服务器环境进行优化的 Java 框架。
它提供快速启动时间和低内存消耗,使其成为云原生应用程序的理想选择。

感谢 JBang,我们可以创建利用该框架强大功能的单文件 Quarkus 应用程序。
以下示例显示了一个测试字符串是否为回文的 REST API。它具有 JSON 解析、日志记录并提供 OpenAPI 和 Swagger 文档。

> jbang init helloworld.java
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

我们可能会注意到脚本中的 //SOURCES PalindromeService.java 行。
它告诉 JBang 在与脚本相同的目录中查找名为 PalindromeService.java 的文件。
这意味着JBang支持多文件脚本。

您可以使用 jbang palqrest@yostane/cours-java 运行服务器并使用curl http://localhost:8080/palindrome?input=madam 调用端点。

> jbang helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

其他语言

JBang 支持运行 Java、Kotlin、JShell 和 Groovy 代码。
它甚至可以从 Markdown 文件运行 Java 代码。
以下是如何在不同语言中使用 JBang 的一些示例:

  • Kotlin:您可以使用 jbang init -t hello.kt filename.kt 初始化 Kotlin 脚本。请注意,这与官方 .main.kts Kotlin 脚本不同。事实上,JBang 创建的 Kotlin 脚本可以受益于目录和 App Store 功能。以下是使用 JBang 创建的 Kotlin 脚本的示例。
> jbang init helloworld.java
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
  • 有趣的事实:JBang 的想法来自针对 Kotlin 生态系统的 kscript。
  • Kotlin 已经具有原生脚本支持(使用 .main.kts 脚本),但似乎缺乏目录、模板和 App Store 功能。
    • Groovy:使用 jbang init -t hello.groovy filename.groovy 初始化 Groovy 脚本。以下是使用 JBang 创建的 Groovy 脚本的示例。
> jbang helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
  • JShell:JBang 支持带有 .jsh 或 .jshell 扩展名的 JShell 脚本以及使用 jbang -c 'System.out.println("Inline Java ☕ yay!")' 的内联脚本。以下是使用 JBang 创建的 JShell 脚本示例。
///usr/bin/env jbang "<pre class="brush:php;toolbar:false">> chmod +x helloworld.java
> ./helloworld.java
Hello world
登录后复制
登录后复制
登录后复制
登录后复制
" "$@" ; exit $? import static java.lang.System.*; public class helloworld { public static void main(String... args) { out.println("Hello world"); } }
  • 使用 Java 和 JShell 代码块进行 Markdown:您可以使用 jbang my_markdown.md 直接从 Markdown 文件运行 Java 和 JShell 代码块。
/// usr/bin/env jbang "<pre class="brush:php;toolbar:false">///usr/bin/env jbang "<pre class="brush:php;toolbar:false">//JAVA 23+
//COMPILE_OPTIONS --enable-preview -source 23
//RUNTIME_OPTIONS --enable-preview
登录后复制
登录后复制
登录后复制
" "$@" ; exit $? //JAVA 23+ //COMPILE_OPTIONS --enable-preview -source 23 //RUNTIME_OPTIONS --enable-preview void main(String... args) { System.out.println("Hello World"); } " "$@" ; exit $? //JAVA 25 //COMPILE_OPTIONS --enable-preview -source 25 //RUNTIME_OPTIONS --enable-preview import java.util.concurrent.Callable; import java.util.concurrent.StructuredTaskScope; import static java.lang.System.*; void main(String... args) { out.println("Hello Java 25"); Callable task1 = () -> { out.println("Task 1" + Thread.currentThread()); return "Task 1"; }; Callable task2 = () -> { out.println("Task 2" + Thread.currentThread()); return 2; }; try ( var scope = new StructuredTaskScope()) { StructuredTaskScope.Subtask subtask1 = scope.fork(task1); StructuredTaskScope.Subtask subtask2 = scope.fork(task2); scope.join(); } catch (Exception e) { e.printStackTrace(); } }

以上是JBang,Java 生态系统中缺失的脚本工具的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板