使用 Quarkus 进行脚本编程
Quarkus 集成了 jbang,您可以使用它来编写 Java 脚本/应用程序,而无需 Maven 或 Gradle 即可运行。
在本指南中,我们将了解如何仅使用单个 Java 文件编写 REST 应用程序。
此技术被认为是预览版。 在预览中,不保证向后兼容性和在生态系统中的存在。 具体改进可能需要更改配置或 API,并且成为稳定的计划正在进行中。 欢迎在我们的邮件列表或我们的GitHub 问题跟踪器上提供反馈。 有关可能的完整状态列表,请查看我们的常见问题解答条目。 |
解决方案
通常我们会链接到 Git 仓库进行克隆,但在这种情况下,除了以下内容之外没有其他文件
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.quarkus.platform:quarkus-bom:3.24.4@pom
//DEPS io.quarkus:quarkus-rest
//JAVAC_OPTIONS -parameters
//JAVA_OPTIONS -Djava.util.logging.manager=org.jboss.logmanager.LogManager
import io.quarkus.runtime.Quarkus;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/hello")
@ApplicationScoped
public class quarkusapp {
@GET
public String sayHello() {
return "hello";
}
public static void main(String[] args) {
Quarkus.run(args);
}
@Inject
GreetingService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/greeting/{name}")
public String greeting(String name) {
return service.greeting(name);
}
@ApplicationScoped
static public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
}
架构
在本指南中,我们创建一个简单的应用程序,使用单个源文件提供一个 hello
端点,无需额外的构建文件(如 pom.xml
或 build.gradle
)。 为了演示依赖注入,此端点使用一个 greeting
bean。

创建初始文件
首先,我们需要一个 Java 文件。 JBang 允许您使用以下命令创建初始版本
jbang init scripting/quarkusapp.java
cd scripting
此命令生成一个 .java 文件,您可以在 Linux 和 macOS 上直接运行它,即 ./quarkusapp.java
- 在 Windows 上,您需要使用 jbang quarkusapp.java
。
此初始版本运行时将打印 Hello World
。
生成后,查看 quarkusapp.java
文件。
您会在顶部找到一行类似于
//usr/bin/env jbang "$0" "$@" ; exit $?
在 Linux 和 macOS 上,这一行允许您将其作为脚本运行。 在 Windows 上,此行将被忽略。
接下来的几行
//DEPS <dependency1> <dependency2>
说明如何将依赖项添加到此脚本。 这是 JBang 的一个功能。
继续并更新此行以包括 quarkus-bom
和 quarkus-rest
依赖项,如下所示
//DEPS io.quarkus.platform:quarkus-bom:3.24.4@pom
//DEPS io.quarkus:quarkus-rest
现在,运行 jbang quarkusapp.java
,您将看到 JBang 解决此依赖项并在 Quarkus JBang 集成的帮助下构建 jar。
$ jbang quarkusapp.java
[jbang] Resolving dependencies...
[jbang] Resolving io.quarkus:quarkus-resteasy:3.24.4...Done
[jbang] Dependencies resolved
[jbang] Building jar...
[jbang] Post build with io.quarkus.launcher.JBangIntegration
Mar 22, 2023 9:47:51 A.M. org.jboss.threads.Version <clinit>
INFO: JBoss Threads version 3.5.0.Final
Mar 22, 2023 9:47:51 A.M. io.quarkus.deployment.QuarkusAugmentor run
INFO: Quarkus augmentation completed in 722ms
Hello World
目前,该应用程序没有做任何新的事情。
如何编辑此文件并获得内容辅助?
要在具有内容辅助的 IDE/编辑器中编辑 JBang 脚本,您可以运行 有关更多信息,请参阅 JBang 文档。 |
Jakarta REST 资源
现在让我们用一个使用 Quarkus 功能的类替换该类
import io.quarkus.runtime.Quarkus;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/hello")
@ApplicationScoped
public class quarkusapp {
@GET
public String sayHello() {
return "hello";
}
public static void main(String[] args) {
Quarkus.run(args);
}
}
这是一个非常简单的类,带有一个 main 方法,用于启动带有 REST 端点的 Quarkus,在 "/hello" 上返回“hello”。
为什么有
main 方法?目前需要一个 |
运行应用程序
现在,当您运行该应用程序时,您将看到 Quarkus 启动。
使用:jbang quarkusapp.java
$ jbang quarkusapp.java
[jbang] Building jar...
[jbang] Post build with io.quarkus.launcher.JBangIntegration
Mar 22, 2023 9:48:39 A.M. org.jboss.threads.Version <clinit>
INFO: JBoss Threads version 3.5.0.Final
Mar 22, 2023 9:48:39 A.M. io.quarkus.deployment.QuarkusAugmentor run
INFO: Quarkus augmentation completed in 521ms
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-03-22 09:48:39,891 INFO [io.quarkus] (main) quarkus 999-SNAPSHOT on JVM (powered by Quarkus 3.24.4) started in 0.283s. Listening on: http://0.0.0.0:8080
2023-03-22 09:48:39,904 INFO [io.quarkus] (main) Profile prod activated.
2023-03-22 09:48:39,904 INFO [io.quarkus] (main) Installed features: [cdi, rest, smallrye-context-propagation, vertx]
启动后,您可以请求提供的端点
$ curl -w "\n" https://:8080/hello
hello
之后,点击 CTRL+C
停止应用程序。
使用
curl -w "\n" 自动添加换行符在此示例中,我们使用 |
为什么
quarkus-rest 没有被解析?在第二次运行时,您不应看到一行说它正在解析 |
使用注入
Quarkus 中的依赖注入基于 ArC,ArC 是一种基于 CDI 的依赖注入解决方案,专为 Quarkus 的架构量身定制。 您可以在上下文和依赖注入指南中了解有关它的更多信息。
ArC 作为 quarkus-rest
的依赖项提供,因此您已经可以方便地使用它。
让我们修改应用程序并添加一个配套 bean。
通常您会添加一个单独的类,但由于我们的目标是将所有内容放在一个文件中,因此您将添加一个嵌套类。
在 quarkusapp
类主体内添加以下内容。
@ApplicationScoped
static public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
使用嵌套静态公共类
我们使用嵌套静态公共类而不是顶级类有两个原因
|
编辑 quarksapp
类以注入 GreetingService
并使用它创建一个新端点,您应该得到类似以下内容
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.quarkus.platform:quarkus-bom:3.24.4@pom
//DEPS io.quarkus:quarkus-rest
import io.quarkus.runtime.Quarkus;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/hello")
@ApplicationScoped
public class quarkusapp {
@GET
public String sayHello() {
return "hello";
}
public static void main(String[] args) {
Quarkus.run(args);
}
@Inject
GreetingService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/greeting/{name}")
public String greeting(String name) {
return service.greeting(name);
}
@ApplicationScoped
static public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
}
现在,当您运行 jbang quarkusapp.java
时,您可以检查新端点返回的内容
$ curl -w "\n" https://:8080/hello/greeting/quarkus
hello null
这真是出乎意料,为什么它返回 hello null
而不是 hello quarkus
?
原因是 Quarkus REST(以前的 RESTEasy Reactive)依赖于设置 -parameters
编译器标志,以便能够将 {name}
映射到 name
参数。
我们通过将以下注释指令添加到文件中来解决此问题
//JAVAC_OPTIONS -parameters
现在,当您使用 jbang quarkusapp.java
运行时,端点应该返回您期望的结果
$ curl -w "\n" https://:8080/hello/greeting/quarkus
hello quarkus
调试
要调试应用程序,您可以使用 jbang --debug quarkusapp.java
,并且可以使用您的 IDE 连接到端口 4004; 如果您想使用更传统的 Quarkus 调试端口,可以使用 jbang --debug=5005 quarkusapp.java
。
注意:JBang 调试始终会暂停,因此您需要连接调试器才能运行该应用程序。
日志记录
要在 JBang 的 Quarkus 脚本中使用日志记录,您可以像往常一样配置记录器,例如
public static final Logger LOG = Logger.getLogger(quarkusapp.class);
要使其工作,您需要添加一个 Java 选项,以确保正确初始化日志记录,例如
//JAVA_OPTIONS -Djava.util.logging.manager=org.jboss.logmanager.LogManager
完成此设置后,运行 jbang quarkusapp.java
将按预期进行日志记录和呈现。
配置应用程序
要配置应用程序,您可以像往常一样使用 application.properties
文件,但您需要将它添加到脚本
//FILES application.properties
// ...
@ConfigProperty(name = "prefix", defaultValue = "WG -")
String prefix;
这将使 application.properties
文件可用于脚本,并像往常一样处理配置。
您还可以使用 application.yaml
文件。 为此,您需要将它添加到 application.yaml
文件到脚本中,并包括 quarkus-config-yaml
依赖项
//DEPS io.quarkus:quarkus-config-yaml
//FILES application.yaml
application.properties 和 application.yaml 文件的路径是相对于脚本文件的。 |
作为本机应用程序运行
如果您已安装 native-image
二进制文件并设置了 GRAALVM_HOME
,或者在 Linux 上安装了容器运行时(例如,podman 或 docker),则可以使用 jbang --native quarkusapp.java
构建和运行本机可执行文件
$ jbang --native quarkusapp.java
[jbang] Building jar...
[jbang] Post build with io.quarkus.launcher.JBangIntegration
Mar 22, 2023 9:58:47 A.M. org.jboss.threads.Version <clinit>
INFO: JBoss Threads version 3.5.0.Final
Mar 22, 2023 9:58:47 A.M. io.quarkus.deployment.pkg.steps.JarResultBuildStep buildNativeImageThinJar
INFO: Building native image source jar: /tmp/quarkus-jbang8082065952748314720/quarkus-application-native-image-source-jar/quarkus-application-runner.jar
Mar 22, 2023 9:58:47 A.M. io.quarkus.deployment.pkg.steps.NativeImageBuildStep build
INFO: Building native image from /tmp/quarkus-jbang8082065952748314720/quarkus-application-native-image-source-jar/quarkus-application-runner.jar
Mar 22, 2023 9:58:47 A.M. io.quarkus.deployment.pkg.steps.NativeImageBuildStep getNativeImageBuildRunner
WARN: Cannot find the `native-image` in the GRAALVM_HOME, JAVA_HOME and System PATH. Attempting to fall back to container build.
Mar 22, 2023 9:58:47 A.M. io.quarkus.deployment.pkg.steps.NativeImageBuildContainerRunner <init>
INFO: Using docker to run the native image builder
Mar 22, 2023 9:58:47 A.M. io.quarkus.deployment.pkg.steps.NativeImageBuildContainerRunner setup
INFO: Checking image status quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17
Mar 22, 2023 9:58:51 A.M. io.quarkus.deployment.pkg.steps.NativeImageBuildStep checkGraalVMVersion
INFO: Running Quarkus native-image plugin on native-image 22.3.1.0-Final Mandrel Distribution (Java Version 17.0.6+10)
Mar 22, 2023 9:58:51 A.M. io.quarkus.deployment.pkg.steps.NativeImageBuildRunner build
INFO: docker run --env LANG=C --rm --user 1000:1000 -v /tmp/quarkus-jbang8082065952748314720/quarkus-application-native-image-source-jar:/project:z --name build-native-XaZUc quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17 -J-Dsun.nio.ch.maxUpdateArraySize=100 -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dlogging.initial-configurator.min-level=500 -J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory -J-Dvertx.disableDnsResolver=true -J-Dio.netty.noUnsafe=true -J-Dio.netty.leakDetection.level=DISABLED -J-Dio.netty.allocator.maxOrder=3 -J-Duser.language=en -J-Duser.country=IE -J-Dfile.encoding=UTF-8 --features=io.quarkus.runner.Feature,io.quarkus.runtime.graal.DisableLoggingFeature -J--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED -J--add-opens=java.base/java.text=ALL-UNNAMED -J--add-opens=java.base/java.io=ALL-UNNAMED -J--add-opens=java.base/java.lang.invoke=ALL-UNNAMED -J--add-opens=java.base/java.util=ALL-UNNAMED -H:+CollectImageBuildStatistics -H:ImageBuildStatisticsFile=quarkus-application-runner-timing-stats.json -H:BuildOutputJSONFile=quarkus-application-runner-build-output-stats.json -H:+AllowFoldMethods -J-Djava.awt.headless=true --no-fallback --link-at-build-time -H:+ReportExceptionStackTraces -H:-AddAllCharsets --enable-url-protocols=http -H:NativeLinkerOption=-no-pie -H:-UseServiceLoaderFeature -H:+StackTrace -J--add-exports=org.graalvm.sdk/org.graalvm.nativeimage.impl=ALL-UNNAMED --exclude-config io\.netty\.netty-codec /META-INF/native-image/io\.netty/netty-codec/generated/handlers/reflect-config\.json --exclude-config io\.netty\.netty-handler /META-INF/native-image/io\.netty/netty-handler/generated/handlers/reflect-config\.json quarkus-application-runner -jar quarkus-application-runner.jar
Mar 22, 2023 9:37:56 A.M. io.quarkus.deployment.pkg.steps.NativeImageBuildRunner runCommand
INFO: docker run --env LANG=C --rm --user 1000:1000 -v /tmp/quarkus-jbang9315448339582904220/quarkus-application-native-image-source-jar:/project:z --entrypoint /bin/bash quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17 -c objcopy --strip-debug quarkus-application-runner
Mar 22, 2023 9:37:57 A.M. io.quarkus.deployment.QuarkusAugmentor run
INFO: Quarkus augmentation completed in 31729ms
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-03-22 09:37:57,471 INFO [io.quarkus] (main) quarkus 999-SNAPSHOT native (powered by 3.24.4) started in 0.009s. Listening on: http://0.0.0.0:8080
2023-03-22 09:37:57,472 INFO [io.quarkus] (main) Profile prod activated.
2023-03-22 09:37:57,472 INFO [io.quarkus] (main) Installed features: [cdi, rest, smallrye-context-propagation, vertx]
此本机构建在首次运行时会花费一些时间,但是任何后续运行(在不更改 quarkusapp.java
的情况下)都会接近即时,这要归功于 JBang 缓存
$ jbang --native quarkusapp.java
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-03-22 09:38:45,450 INFO [io.quarkus] (main) quarkus 999-SNAPSHOT native (powered by 3.24.4) started in 0.009s. Listening on: http://0.0.0.0:8080
2023-03-22 09:38:45,450 INFO [io.quarkus] (main) Profile prod activated.
2023-03-22 09:38:45,450 INFO [io.quarkus] (main) Installed features: [cdi, rest, smallrye-context-propagation, vertx]
使用 Qute
您可以通过添加 quarkus-qute
依赖项在 JBang 脚本中使用 Qute 模板引擎。 您还需要将 templates
目录包含在脚本中
//DEPS io.quarkus:quarkus-qute
//FILES templates/=templates/*
// ...
@Inject
Template template; // Locate and load the `templates/template.html` file
如果您的 templates
目录包含子目录,请使用 templates/=templates/**/
代替。
结论
如果您想开始使用 Quarkus 或快速编写一些内容,Quarkus Scripting with jbang 可让您做到这一点。 没有 Maven,没有 Gradle - 只有一个 Java 文件。 在本指南中,我们概述了使用带有 JBang 的 Quarkus 的最基本知识; 如果您想了解有关 JBang 可以做什么的更多信息,请访问 https://jbang.dev。