Scripting with Quarkus
Quarkus 提供与 jbang 的集成,允许你编写 Java 脚本/应用程序,无需 Maven 或 Gradle 便能运行。
Quarkus provides integration with jbang which allows you to write Java scripts/applications requiring no Maven nor Gradle to get running.
在本指南中,我们将了解如何仅使用一个 Java 文件编写 REST 应用程序。
In this guide, we will see how you can write a REST application using just a single Java file. Unresolved directive in scripting.adoc - include::{includes}/extension-status.adoc[]
Solution
我们通常会链接到 Git 存储库以便克隆,但在这种情况下,除了以下文件以外,没有其他文件:
Normally we would link to a Git repository to clone but in this case there is no additional files than the following:
//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。
In this guide, we create a straightforward application serving a hello
endpoint with a single source file, no additional build files like pom.xml
or build.gradle
needed. To demonstrate dependency injection, this endpoint uses a greeting
bean.
Creating the initial file
首先,我们需要一个 Java 文件。JBang 允许你使用以下命令创建一个初始版本:
First, we need a Java file. JBang lets you create an initial version using:
jbang init scripting/quarkusapp.java
cd scripting
此命令会生成一个 .java 文件,你可以在 Linux 和 macOS 中直接运行它,即 ./quarkusapp.java
,在 Windows 中你需要使用 jbang quarkusapp.java
。
This command generates a .java file that you can directly run on Linux and macOS, i.e. ./quarkusapp.java
- on Windows you need to use jbang quarkusapp.java
.
此初始版本运行后将打印 Hello World
。
This initial version will print Hello World
when run.
生成后,查看 quarkusapp.java
文件。
Once generated, look at the quarkusapp.java
file.
你会在顶部找到一行类似于此的内容:
You will find at the top a line looking like this:
//usr/bin/env jbang "$0" "$@" ; exit $?
在 Linux 和 macOS 中,此行允许你将其作为一个脚本运行。在 Windows 中,此行为被忽略。
This line is what on Linux and macOS allows you to run it as a script. On Windows this line is ignored.
接下来的几行
The next lines
//DEPS <dependency1> <dependency2>
说明了你如何向这个脚本添加依赖项。这是 JBang 的一项功能。
illustrate how you add dependencies to this script. This is a feature of JBang.
继续并更新此行以包括 quarkus-bom
和 quarkus-rest
依赖项,如下所示:
Go ahead and update this line to include the quarkus-bom
and the quarkus-rest
dependency like so:
//DEPS {quarkus-platform-groupid}:quarkus-bom:{quarkus-version}@pom
//DEPS io.quarkus:quarkus-rest
现在,运行 jbang quarkusapp.java
,你将看到 JBang 解析此依赖项并借助 Quarkus 的 JBang 集成构建 jar。
Now, run jbang quarkusapp.java
and you will see JBang resolving this dependency and building the jar with help from Quarkus' JBang integration.
$ 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
目前,应用程序没有新的功能。
For now the application does nothing new.
How do I edit this file and get content assist?
如需在带有内容辅助的 IDE/编辑器中编辑 JBang 脚本,你可以运行 To edit the JBang script in an IDE/editor with content assist you can run 有关更多信息,请参阅 the JBang documentation。 For more information please refer to the the JBang documentation. |
The Jakarta REST resources
下面让我们用一个使用 Quarkus 特性的类替换之前的类:
Now let us replace the class with one that uses Quarkus features:
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"。
It’s a very simple class with a main method that starts Quarkus with a REST endpoint, returning "hello" to requests on "/hello".
Why is the
main method there?一个 A |
Running the application
现在,当你运行应用程序时,你会看到 Quarkus 启动。
Now when you run the application you will see Quarkus start up.
使用: jbang quarkusapp.java
:
Use: 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]
一旦启动,你可以请求提供的端点:
Once started, you can request the provided endpoint:
$ curl -w "\n" http://localhost:8080/hello
hello
之后,点击 CTRL+C
停止应用程序。
After that, hit CTRL+C
to stop the application.
Automatically add newline with
curl -w "\n" 我们在本例中使用 `curl -w "\n"`是为了避免你的终端打印一个 '%' 或把结果和下一个命令提示放在同一行。 We are using |
Why is
quarkus-rest not resolved?在第二次运行中,你应该不会看到一行话,说正在解决 In this second run you should not see a line saying it is resolving |
Using injection
Quarkus 中的依赖注入基于 ArC,ArC 是一种基于 CDI 的依赖注入解决方案,专为 Quarkus 的架构定制。你可以在 Contexts and Dependency Injection guide 中了解更多信息。
Dependency injection in Quarkus is based on ArC which is a CDI-based dependency injection solution tailored for Quarkus' architecture. You can learn more about it in the Contexts and Dependency Injection guide.
ArC 作为 quarkus-rest
的依赖项附带提供,所以你已经手边有它了。
ArC comes as a dependency of quarkus-rest
so you already have it handy.
让我们修改应用程序并添加一个伴随 Bean。
Let’s modify the application and add a companion bean.
通常情况下,你将添加一个单独的类,但由于我们的目标是将其全部放在一个文件中,你将添加一个嵌套类。
Normally you would add a separate class, but as we are aiming to have it all in one file you will add a nested class.
在 quarkusapp
类体中添加以下 inside。
Add the following inside the quarkusapp
class body.
@ApplicationScoped
static public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
Use of nested static public classes
出于两个原因,我们使用嵌套静态 public 类而不是顶级类: We are using a nested static public class instead of a top level class for two reasons:
|
编辑 quarksapp
类以注入 GreetingService
,并使用它创建一个新的端点,你应该最终得到如下内容:
Edit the quarksapp
class to inject the GreetingService
and create a new endpoint using it, you should end up with something like:
//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
时,您可以检查新端点的返回内容:
Now when you run jbang quarkusapp.java
you can check what the new end point returns:
$ curl -w "\n" http://localhost:8080/hello/greeting/quarkus
hello null
这是预料之外的,为什么它会返回 hello null
而不是 hello quarkus
?
Now that is unexpected, why is it returning hello null
and not hello quarkus
?
原因是 Quarkus REST(前身为 RESTEasy Reactive)依赖于 -parameters
编译器标志,以能够将 {name}
映射到 name
参数。
The reason is that Quarkus REST (formerly RESTEasy Reactive) relies on the -parameters
compiler flag to be set to be able to map {name}
to the name
parameter.
我们通过将以下注释指令添加到文件中来修复它:
We fix that by adding the following comment instruction to the file:
//JAVAC_OPTIONS -parameters
现在,当您使用 jbang quarkusapp.java
运行时,端点应该返回您期望的内容:
Now when you run with jbang quarkusapp.java
the end point should return what you expect:
$ curl -w "\n" http://localhost:8080/hello/greeting/quarkus
hello quarkus
Debugging
要调试应用程序,您使用 jbang --debug quarkusapp.java
,并且可以使用您的 IDE 连接到端口 4004;如果您希望使用更传统的 Quarkus 调试端口,则可以使用 jbang --debug=5005 quarkusapp.java
。
To debug the application you use jbang --debug quarkusapp.java
and you can use your IDE to connect on port 4004; if you want to use the
more traditional Quarkus debug port you can use jbang --debug=5005 quarkusapp.java
.
注意:JBang 调试始终暂停,因此您需要连接调试器才能运行应用程序。
Note: JBang debugging always suspends thus you need to connect the debugger to have the application run.
Logging
要使用 JBang 在 Quarkus 脚本中进行日志记录,您需要像往常一样配置一个记录器,即:
To use logging in Quarkus scripting with JBang you do as usual, with configuring a logger, i.e.
public static final Logger LOG = Logger.getLogger(quarkusapp.class);
为了使其正常工作,您需要添加一个 Java 选项以确保日志记录正确初始化,即:
To get it to work you need to add a Java option to ensure the logging is initialized properly, i.e.
//JAVA_OPTIONS -Djava.util.logging.manager=org.jboss.logmanager.LogManager
现在运行 jbang quarkusapp.java
,日志和渲染将按预期进行。
With that in place running jbang quarkusapp.java
will log and render as expected.
Configuring Application
要配置应用程序,您通常可以使用 application.properties
文件,但您需要将其 add 到脚本中:
To configure the application you can use the application.properties
file as usual, but you need to add it to the script:
//FILES application.properties
// ...
@ConfigProperty(name = "prefix", defaultValue = "WG -")
String prefix;
这将使 application.properties
文件可用于脚本,并像往常一样处理配置。
This will make the application.properties
file available to the script, and process the configuration as usual.
您还可以使用 application.yaml
文件。为此,您需要将其 add 到 application.yaml
文件到脚本中,并包含 quarkus-config-yaml
依赖项:
You can also use the application.yaml
file.
For this, you need to add it to the application.yaml
file to the script and include the quarkus-config-yaml
dependency:
//DEPS io.quarkus:quarkus-config-yaml
//FILES application.yaml
|
The path to the |
Running as a native application
如果您已安装 native-image
二进制文件并设置了 GRAALVM_HOME
,或在 Linux 中安装了容器运行时(例如 podman 或 docker),则可以使用 jbang --native quarkusapp.java
获取本机可执行文件并运行:
If you have the native-image
binary installed and GRAALVM_HOME
set, or a container runtime (e.g., podman or docker) installed on Linux, you can get the native executable built and run using 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 缓存而几乎是即时的:
This native build will take some time on first run but any subsequent runs (without changing quarkusapp.java
) will be close to instant thanks to JBang cache:
$ 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
目录:
You can use the Qute templating engine in your JBang script by adding the quarkus-qute
dependency.
You also need to include the templates
directory in the script:
//DEPS io.quarkus:quarkus-qute
//FILES templates/=templates/*
// ...
@Inject
Template template; // Locate and load the `templates/template.html` file
如果您的 templates
目录包含子目录,请使用 templates/=templates/*/
代替。
If your templates
directory includes sub-directories, use templates/=templates/*/
instead.
Conclusion
如果您想开始使用 Quarkus 或快速编写一些内容,那么使用 jbang 的 Quarkus 脚本可让您做到这一点。无需 Maven,无需 Gradle - 只需一个 Java 文件。在本指南中,我们概述了使用 JBang 的 Quarkus 的基本知识;如果您想详细了解 JBang 的功能,请参阅 [role="bare"][role="bare"]https://jbang.dev。
If you want to get started with Quarkus or write something quickly, Quarkus Scripting with jbang lets you do that. No Maven, no Gradle - just a Java file. In this guide we outlined the very basics on using Quarkus with JBang; if you want to learn more about what JBang can do, go see [role="bare"]https://jbang.dev.