Scripting with Quarkus
Prerequisites
如要完成本指南,您需要:
-
Roughly 15 minutes
-
An IDE
-
安装了 JDK 17+,已正确配置
JAVA_HOME
-
Apache Maven ${proposed-maven-version}
-
如果你想使用 Quarkus CLI, 则可以选择使用
-
如果你想构建一个本机可执行文件(或如果你使用本机容器构建,则使用 Docker),则可以选择安装 Mandrel 或 GraalVM 以及 configured appropriately
Solution
我们通常会链接到 Git 存储库以便克隆,但在这种情况下,除了以下文件以外,没有其他文件:
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS {quarkus-platform-groupid}:quarkus-bom:{quarkus-version}@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;
}
}
}
Architecture
在本指南中,我们使用单个源文件创建一个简单的应用程序,该应用程序提供一个 hello
端点,无需 pom.xml
或 build.gradle
等其他构建文件。为了演示依赖注入,此端点使用 greeting
bean。
Creating the initial file
首先,我们需要一个 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 {quarkus-platform-groupid}:quarkus-bom:{quarkus-version}@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:{quarkus-version}...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
目前,应用程序没有新的功能。
How do I edit this file and get content assist?
如需在带有内容辅助的 IDE/编辑器中编辑 JBang 脚本,你可以运行 |
The Jakarta REST resources
下面让我们用一个使用 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"。
Why is the
main method there?一个 |
Running the application
现在,当你运行应用程序时,你会看到 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 {quarkus-version}) 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" http://localhost:8080/hello
hello
之后,点击 CTRL+C
停止应用程序。
Automatically add newline with
curl -w "\n" 我们在本例中使用 `curl -w "\n"`是为了避免你的终端打印一个 '%' 或把结果和下一个命令提示放在同一行。 |
Why is
quarkus-rest not resolved?在第二次运行中,你应该不会看到一行话,说正在解决 |
Using injection
Quarkus 中的依赖注入基于 ArC,ArC 是一种基于 CDI 的依赖注入解决方案,专为 Quarkus 的架构定制。你可以在 Contexts and Dependency Injection guide 中了解更多信息。
ArC 作为 quarkus-rest
的依赖项附带提供,所以你已经手边有它了。
让我们修改应用程序并添加一个伴随 Bean。
通常情况下,你将添加一个单独的类,但由于我们的目标是将其全部放在一个文件中,你将添加一个嵌套类。
在 quarkusapp
类体中添加以下 inside。
@ApplicationScoped
static public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
Use of nested static public classes
出于两个原因,我们使用嵌套静态 public 类而不是顶级类:
|
编辑 quarksapp
类以注入 GreetingService
,并使用它创建一个新的端点,你应该最终得到如下内容:
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.quarkus.platform:quarkus-bom:{quarkus-version}@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" http://localhost: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" http://localhost:8080/hello/greeting/quarkus
hello quarkus
Debugging
要调试应用程序,您使用 jbang --debug quarkusapp.java
,并且可以使用您的 IDE 连接到端口 4004;如果您希望使用更传统的 Quarkus 调试端口,则可以使用 jbang --debug=5005 quarkusapp.java
。
注意:JBang 调试始终暂停,因此您需要连接调试器才能运行应用程序。
Logging
要使用 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
,日志和渲染将按预期进行。
Configuring Application
要配置应用程序,您通常可以使用 application.properties
文件,但您需要将其 add 到脚本中:
//FILES application.properties
// ...
@ConfigProperty(name = "prefix", defaultValue = "WG -")
String prefix;
这将使 application.properties
文件可用于脚本,并像往常一样处理配置。
您还可以使用 application.yaml
文件。为此,您需要将其 add 到 application.yaml
文件到脚本中,并包含 quarkus-config-yaml
依赖项:
//DEPS io.quarkus:quarkus-config-yaml
//FILES application.yaml
|
Running as a native application
如果您已安装 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. Install it using `gu install native-image` 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 {quarkus-version}) 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 {quarkus-version}) 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]
Using Qute
您可以在 JBang 脚本中使用 Qute templating engine,方法是添加 quarkus-qute
依赖项。您还需要在脚本中包含 templates
目录:
//DEPS io.quarkus:quarkus-qute
//FILES templates/=templates/*
// ...
@Inject
Template template; // Locate and load the `templates/template.html` file
如果您的 templates
目录包含子目录,请使用 templates/=templates/*/
代替。
Conclusion
如果您想开始使用 Quarkus 或快速编写一些内容,那么使用 jbang 的 Quarkus 脚本可让您做到这一点。无需 Maven,无需 Gradle - 只需一个 Java 文件。在本指南中,我们概述了使用 JBang 的 Quarkus 的基本知识;如果您想详细了解 JBang 的功能,请参阅 [role="bare"][role="bare"]https://jbang.dev。