Quarkus によるスクリプティング
Quarkus は Maven も Gradleも必要としない Java のスクリプトおよびアプリケーションを記述することができる jbang との統合を提供しています。
このガイドでは、1つの Java ファイルだけを使って REST アプリケーションを書く方法を見ていきます。
この技術は、previewと考えられています。 preview では、下位互換性やエコシステムでの存在は保証されていません。具体的な改善には設定や API の変更が必要になるかもしれませんが、 stable になるための計画は現在進行中です。フィードバックは メーリングリスト や GitHub の課題管理 で受け付けています。 とりうるステータスの完全なリストについては、 FAQの項目 を参照してください。 |
ソリューション
通常は Git リポジトリに関連付けてクローンしますが、今回利用するのは以下のファイルだけです。
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.quarkus.platform:quarkus-bom:2.16.4.Final@pom
//DEPS io.quarkus:quarkus-resteasy-reactive
//JAVAC_OPTIONS -parameters
//JAVA_OPTIONS -Djava.util.logging.manager=org.jboss.logmanager.LogManager
import io.quarkus.runtime.Quarkus;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jboss.logging.Logger;
@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 を使うと、次のように初期バージョンの Java ファイルを作成することができます。
jbang init scripting/quarkusapp.java
cd scripting
このコマンドは、Linux と macOS で直接実行できる .java ファイルとして ./quarkusapp.java
を生成します。Windows では、jbang quarkusapp.java
を使用する必要があります。
この初期バージョンを実行すると Hello World
を表示します。
生成された quarkusapp.java
ファイルを確認します。
一番上にこのような行があります。
//usr/bin/env jbang "$0" "$@" ; exit $?
この行は、Linux や macOS でスクリプトとして実行できるようにするためのものです。Windowsでは、この行は無視されます。
次の行
// //DEPS <dependency1> <dependency2>
このスクリプトに依存関係を追加する方法を示しています。これは jbang
の機能です。
この行を quarkus-resteasy
の依存関係を含むように更新します。
//DEPS io.quarkus.platform:quarkus-bom:2.16.4.Final@pom
//DEPS io.quarkus:quarkus-resteasy-reactive
ここで jbang quarkusapp.java
を実行すると、 jbang
がこの依存関係を解決し、Quarkus の jbang 統合の機能を利用して jar をビルドしていることがわかります。
$ jbang quarkusapp.java
[jbang] Resolving dependencies...
[jbang] Resolving io.quarkus:quarkus-resteasy:2.16.4.Final...Done
[jbang] Dependencies resolved
[jbang] Building jar...
[jbang] Post build with io.quarkus.launcher.JBangIntegration
Aug 30, 2020 5:40:55 AM org.jboss.threads.Version <clinit>
INFO: JBoss Threads version 3.1.1.Final
Aug 30, 2020 5:40:56 AM io.quarkus.deployment.QuarkusAugmentor run
INFO: Quarkus augmentation completed in 722ms
Hello World
ここまでは、このアプリケーションは特に新しい動作をしていません。
このファイルの編集時にコンテンツアシスト機能を利用する方法
Linux/macOS では、 編集中に依存関係を追加した場合は、 |
JAX-RSリソース
これを Quarkus の機能を使用するクラスに置き換えてみます。
import io.quarkus.runtime.Quarkus;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@Path("/hello")
@ApplicationScoped
public class quarkusapp {
@GET
public String sayHello() {
return "hello";
}
public static void main(String[] args) {
Quarkus.run(args);
}
}
Quarkus で REST エンドポイントを起動し、「/hello」へのリクエスト対して「hello」を返すメインメソッドを持つ、非常にシンプルなクラスです。
main メソッドが存在する理由現時点で |
アプリケーションの実行
アプリケーションを実行すると、 Quarkus が起動するのを確認することができます。
jbang quarkusapp.java
の利用
$ jbang quarkusapp.java
[jbang] Building jar...
[jbang] Post build with io.quarkus.launcher.JBangIntegration
Aug 30, 2020 5:49:01 AM org.jboss.threads.Version <clinit>
INFO: JBoss Threads version 3.1.1.Final
Aug 30, 2020 5:49:02 AM io.quarkus.deployment.QuarkusAugmentor run
INFO: Quarkus augmentation completed in 681ms
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2020-08-30 05:49:03,255 INFO [io.quarkus] (main) Quarkus 2.16.4.Final on JVM started in 0.638s. Listening on: http://0.0.0.0:8080
2020-08-30 05:49:03,272 INFO [io.quarkus] (main) Profile prod activated.
2020-08-30 05:49:03,272 INFO [io.quarkus] (main) Installed features: [cdi, resteasy-reactive]
起動後、提供されたエンドポイントにリクエストを送信することができます。
$ curl -w "\n" http://localhost:8080/hello
hello
その後 CTRL+C
を入力し、アプリケーションを停止させます。
curl -w "\n" で自動的に改行が追加されるようにします。この例では |
quarkus-resteasy-reactive が解決されない理由1回めの実行で jbang が依存関係の解決をキャッシュしているため、2回目の実行では |
依存性注入の使用
Quarkus の依存性注入は、Quarkus のアーキテクチャに合わせて調整された CDI ベースの依存性注入ソリューションである ArC をベースにしています。 ArC の詳細については、コンテキストと依存性注入ガイド を参照してください。
ArCは quarkus-resteasy
の依存関係として提供されるため、新たに追加する必要はありません。
アプリケーションを修正してコンパニオンクラスのBeanを追加してみます。
通常は別のクラスを追加しますが、一つのファイルにまとめるために、ネストされたクラスを追加します。
quarkusapp
クラスの 内側に 以下を追加します。
@ApplicationScoped
static public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
ネストされた静的パブリッククラスの使用
トップレベルのクラスではなく、ネストされた静的パブリッククラスを使用しているのには、2つの理由があります。
|
quarksapp
クラスを編集して GreetingService
を注入し、それを使って新しいエンドポイントを作成します。
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.quarkus:quarkus-resteasy-reactive:2.16.4.Final
import io.quarkus.runtime.Quarkus;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello")
@ApplicationScoped
public class quarkusapp {
@GET
public String sayHello() {
return "hello from Quarkus with jbang.dev";
}
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 quarkus
ではなく hello null
が返却されます。この理由は何でしょうか?
これは、RESTEasy Reactive が name
パラメータに {name}
をマップできるようにするために -parameters
コンパイラーフラグをセットすることに依存しているからです。
ファイルに以下のコメント命令文を追加することで修正します。
//JAVAC_OPTIONS -parameters
jbang quarkusapp.java
を実行すると、エンドポイントは期待通りの値を返すようになったことが確認できます。
$ curl -w "\n" http://localhost: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
を実行すると、期待通りにロギングが行われます。
アプリケーションの設定
アプリケーションの静的な設定を行うために、 //Q:CONFIG <property>=<value>
を使用することができます。
例えば smallrye-openapi
と swagger-ui
のエクステンションを追加して Swagger UI を常に表示させたい場合は、以下のように追加します。
//DEPS io.quarkus:quarkus-smallrye-openapi:2.16.4.Final
//DEPS io.quarkus:quarkus-swagger-ui:2.16.4.Final
//Q:CONFIG quarkus.swagger-ui.always-include=true
これでビルドによって出来上がるjar内に quarkus.swagger-ui.always-include
が生成されるようになり、実行時に http://0.0.0.0:8080/q/swagger-ui
が利用可能になります。
ネイティブアプリケーションとしての実行
native-image
バイナリーがインストールされていて GRAALVM_HOME
が設定されている場合は、 jbang --native quarkusapp.java
を使用してネイティブ実行可能ファイルをビルドして実行することができます。
$ jbang --native quarkusapp.java
[jbang] Building jar...
[jbang] Post build with io.quarkus.launcher.JBangIntegration
Aug 30, 2020 6:21:15 AM org.jboss.threads.Version <clinit>
INFO: JBoss Threads version 3.1.1.Final
Aug 30, 2020 6:21:16 AM io.quarkus.deployment.pkg.steps.JarResultBuildStep buildNativeImageThinJar
INFO: Building native image source jar: /var/folders/yb/sytszfld4sg8vwr1h0w20jlw0000gn/T/quarkus-jbang3291688251685023074/quarkus-application-native-image-source-jar/quarkus-application-runner.jar
Aug 30, 2020 6:21:16 AM io.quarkus.deployment.pkg.steps.NativeImageBuildStep build
INFO: Building native image from /var/folders/yb/sytszfld4sg8vwr1h0w20jlw0000gn/T/quarkus-jbang3291688251685023074/quarkus-application-native-image-source-jar/quarkus-application-runner.jar
Aug 30, 2020 6:21:16 AM io.quarkus.deployment.pkg.steps.NativeImageBuildStep checkGraalVMVersion
INFO: Running Quarkus native-image plugin on GraalVM Version 20.1.0 (Java Version 11.0.7)
Aug 30, 2020 6:21:16 AM io.quarkus.deployment.pkg.steps.NativeImageBuildStep build
INFO: /Users/max/.sdkman/candidates/java/20.1.0.r11-grl/bin/native-image -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dsun.nio.ch.maxUpdateArraySize=100 -J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory -J-Dvertx.disableDnsResolver=true -J-Dio.netty.leakDetection.level=DISABLED -J-Dio.netty.allocator.maxOrder=1 -J-Duser.language=en -J-Dfile.encoding=UTF-8 --initialize-at-build-time= -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy\$BySpaceAndTime -H:+JNI -jar quarkus-application-runner.jar -H:FallbackThreshold=0 -H:+ReportExceptionStackTraces -H:-AddAllCharsets -H:EnableURLProtocols=http --no-server -H:-UseServiceLoaderFeature -H:+StackTrace quarkus-application-runner
Aug 30, 2020 6:22:31 AM io.quarkus.deployment.QuarkusAugmentor run
INFO: Quarkus augmentation completed in 76010ms
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2020-08-30 06:22:32,012 INFO [io.quarkus] (main) Quarkus 2.16.4.Final native started in 0.017s. Listening on: http://0.0.0.0:8080
2020-08-30 06:22:32,013 INFO [io.quarkus] (main) Profile prod activated.
2020-08-30 06:22:32,013 INFO [io.quarkus] (main) Installed features: [cdi, resteasy-reactive]
このネイティブビルドは最初の実行には時間がかかりますが、その後は ( quarkusapp.java
を変更せずに) jbang キャッシュのおかげですぐに実行できるようになります。
$ jbang --native quarkusapp.java
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2020-08-30 06:23:36,846 INFO [io.quarkus] (main) Quarkus 2.16.4.Final native started in 0.015s. Listening on: http://0.0.0.0:8080
2020-08-30 06:23:36,846 INFO [io.quarkus] (main) Profile prod activated.
2020-08-30 06:23:36,846 INFO [io.quarkus] (main) Installed features: [cdi, resteasy-reactive]
まとめ
Quarkusを使い始めたい、または何かを素早くコーディングしたい場合、 jbang による Quarkus スクリプティングを使用すると便利です。Java ファイルだけでよく、Maven や Gradle は必要ありません。このガイドでは、JBang を使用した Quarkus の基本的な使い方を説明しました。JBangでできることの詳細については、 https://jbang.dev を参照してください。