これは、なにをしたくて書いたもの?
WildFly Bootable JARというものが便利そうだったので、ちょっと試してみることにしました。
WildFly Bootable JARとは?
WildFly Bootable JARとはWildFly Bootable JAR Maven Pluginを使って作成する、実行可能JARファイル(WildFly Bootable JAR)を
作る仕組みです。
GitHub - wildfly-extras/wildfly-jar-maven-plugin: WildFly Bootable JAR
WildFly Bootable JAR is final!
単純化して言うと、WARなどのアプリケーションにWildFlyを追加して、WildFlyを含めて実行可能なJARファイルにする
仕組みのようです。
Spring Bootみたいですね。
WildFly Bootable JAR Maven Plugiinを使って作成したWildFly Bootable JARは、通常のWildFlyと同様に動作するそうです。
WildFly CLIを使って操作できることもできるとか。
制限事項は、以下だそうです。
ドキュメントは、こちらです。
WildFly Bootable JAR Documentation
WildFly側のドキュメントにも、記載があります。
いずれも、WildFlyのドキュメントのトップからたどれますね。
登場したのは、WildFly 20からのようです。
ところで、こう書くとQuarkusがあるのでは?とも思ったりするのですが、Quarkusは直接はWildFlyの代わりにはならないので
あくまでJakarta EEを使用したアプリケーションを実行可能JARとしたい場合は、こちらの仕組みを使うのがよいのでしょうね。
できることを、もう少し?
WildFly Bootable JAR Maven Pluginを使ってできることを、もう少し書いてみましょう。
- Galleon layerを使って、コンポーネントをカスタマイズする
- WildFlyサーバーとして組み込むレイヤーを選択でき、サーバーの構成のカスタマイズ、フットプリントの削減などが可能
- Hollow Bootable JARを作成できる
- デプロイ対象を含まない、Bootable JARを作成可能
- デプロイ対象のWARファイルなどは、実行時に指定できる
- サーバーの構成が可能
- パッケージング中に、WildFly CLIを実行する
- OpenShift/Kubernetes向けに構成する
- 実行中にも変更可能
- サーバーを停止すると、変更は失われる
- 開発モードのサポート
- ソースコードの変更を監視し、変更が行われたら再デプロイする
- デプロイ対象のパッケージを監視して、パッケージが更新されたら再デプロイする
テストでの利用に関しては、Arquillianを使うようです。
https://github.com/wildfly/wildfly-arquillian/tree/3.0.1.Final/container-bootable
各種サンプルは、こちら。
https://github.com/wildfly-extras/wildfly-jar-maven-plugin/tree/5.0.1.Final/examples
というわけで、まずは使ってみましょう。
環境
今回の環境は、こちらです。
$ java --version openjdk 11.0.11 2021-04-20 OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04) OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing) $ mvn --version Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-77-generic", arch: "amd64", family: "unix"
サンプルアプリケーション
まずは、動作確認するためのサンプルアプリケーションを作成します。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>wildfly-bootable-jar-example</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-bom</artifactId> <version>8.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <scope>provided</scope> </dependency> </dependencies> </project>
簡単な、JAX-RS+CDIを使ったWebアプリケーションを用意しましょう。
src/main/java/org/littlewings/jakarta/wildfly/bootable/JaxrsActivator.java
package org.littlewings.jakarta.wildfly.bootable; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("/") public class JaxrsActivator extends Application { }
src/main/java/org/littlewings/jakarta/wildfly/bootable/MessageResource.java
package org.littlewings.jakarta.wildfly.bootable; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; @ApplicationScoped @Path("message") public class MessageResource { @Inject MessageService messageService; @GET @Produces(MediaType.TEXT_PLAIN) public String hello(@QueryParam("word") @DefaultValue("World") String word) { return messageService.message(word); } }
src/main/java/org/littlewings/jakarta/wildfly/bootable/MessageService.java
package org.littlewings.jakarta.wildfly.bootable; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped public class MessageService { public String message(String word) { return String.format("Hello %s!!", word); } }
パッケージングすると、WARファイルができます。
$ mvn package $ ll -h target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT.war -rw-rw-r-- 1 xxxxx xxxxx 4.9K 7月 3 19:01 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT.war
まあ、ふつうです。
WildFly Bootable JAR Maven Pluginを追加する
このサンプルアプリケーションに、WildFly Bootable JAR Maven Pluginを追加してパッケージングしてみましょう。
シンプルには、こんな感じですね。
Adding the bootable JAR Maven plugin to your pom file
<build> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-jar-maven-plugin</artifactId> <version>5.0.1.Final</version> <configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final</feature-pack-location> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
feature-pack-location
で、使用するWildFlyのバージョンを指定します。今回は、24.0.0.Finalです。
Specifying the WildFly server version to use
<configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final</feature-pack-location> </configuration>
バージョンを指定しない場合は、最新のWildFlyが使われます。
こちらは、mvn package
で動作させるためのものです。
<executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions>
この状態でパッケージングすると
$ mvn package
WildFly Bootable JAR Maven Pluginが動作し
[INFO] --- wildfly-jar-maven-plugin:5.0.1.Final:package (default) @ wildfly-bootable-jar-example --- [INFO] Provisioning server configuration based on the standalone-microprofile.xml default configuration [INFO] Building server based on [[wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final inherit-packages=false inheritConfigs=false includedConfigs [model=standalone name=standalone-microprofile.xml]]] galleon feature-packs [INFO] Found boot artifact org.wildfly.core:wildfly-jar-boot:jar:16.0.0.Final:provided in org.wildfly:wildfly-ee-galleon-pack:24.0.0.Final 7月 03, 2021 7:06:42 午後 org.wildfly.core.embedded.LoggerContext$JBossLoggingModuleLogger greeting INFO: JBoss Modules version 1.11.0.Final 7月 03, 2021 7:06:42 午後 org.jboss.msc.service.ServiceContainerImpl <clinit> INFO: JBoss MSC version 1.4.12.Final 7月 03, 2021 7:06:42 午後 org.jboss.threads.Version <clinit> INFO: JBoss Threads version 2.3.2.Final 7月 03, 2021 7:06:42 午後 org.jboss.as.server.ApplicationServerService start INFO: WFLYSRV0049: WildFly Full 24.0.0.Final (WildFly Core 16.0.0.Final) starting 7月 03, 2021 7:06:43 午後 org.jboss.as.patching.installation.InstallationManagerService start INFO: WFLYPAT0050: WildFly Full cumulative patch ID is: base, one-off patches include: none 7月 03, 2021 7:06:43 午後 org.jboss.as.server.suspend.SuspendController resume INFO: WFLYSRV0212: Resuming server 7月 03, 2021 7:06:43 午後 org.jboss.as.server.BootstrapListener done INFO: WFLYSRV0025: WildFly Full 24.0.0.Final (WildFly Core 16.0.0.Final) started in 1091ms - Started 29 of 32 services (3 services are lazy, passive or on-demand) 7月 03, 2021 7:06:43 午後 org.wildfly.security.Version <clinit> INFO: ELY00001: WildFly Elytron version 1.16.0.Final 7月 03, 2021 7:06:45 午後 org.jboss.as.controller.AttributeDefinition validateAndSet INFO: WFLYCTL0028: Attribute 'security-realm' in the resource at address '/subsystem=undertow/server=default-server/https-listener=https' is deprecated, and may be removed in a future version. See the attribute description in the output of the read-resource-description operation to learn more about the deprecation. 7月 03, 2021 7:06:45 午後 org.jboss.as.server.ApplicationServerService stop INFO: WFLYSRV0050: WildFly Full 24.0.0.Final (WildFly Core 16.0.0.Final) stopped in 10ms [INFO] Executing CLI, Server configuration [INFO] CLI scripts execution done.
WARファイル以外に、-bootable.jar
と付いたJARファイルが作成されます。125Mありますけど。
$ ll -h target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT*.* -rw-rw-r-- 1 xxxxx xxxxx 125M 7月 3 19:07 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT-bootable.jar -rw-rw-r-- 1 xxxxx xxxxx 4.9K 7月 3 19:06 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT.war
このJARファイルを実行すると
$ java -jar target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT-bootable.jar
文字通りWildFlyが起動します。
19:08:35,107 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 24.0.0.Final (WildFly Core 16.0.0.Final) started in 4582ms - Started 318 of 463 services (221 services are lazy, passive or on-demand
WARファイルは、ROOT.war
としてデプロイされます。
19:08:35,068 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0010: Deployed "wildfly-bootable-jar-example-0.0.1-SNAPSHOT.war" (runtime-name : "ROOT.war")
このため、コンテキストパスは/
でアクセスできます。
$ curl localhost:8080/message Hello World!! $ curl localhost:8080/message?word=WildFly Hello WildFly!!
動作確認もできましたね。
Bootable JAR実行時に使える引数は、こちら。
起動は、wildfly-jar:run
やwildfly-jar:start
でも行うことができます。
$ mvn package wildfly-jar:run
wildfly-jar:run
とwildfly-jar:start
の違いは、バックグラウンドで動作するかどうかとなります。
wildfly-jar:start
で起動した場合は、wildfly-jar:shutdown
で停止する必要があります。
$ mvn wildfly-jar:shutdown
コンテキストパスを変更する場合は、contextRoot
というWildFly Bootable JAR Maven Pluginの設定で行うようです。
URL context path of deployed application
executionを設定しない場合は?
以下のexecution
の指定を入れない場合、
<executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions>
Bootable JARを作成するためのコマンドはこうなります。
$ mvn package wildfly-jar:package
先にpackage
ゴールを指定しておくことが必須となり、wildfly-jar:package
単体では動作しません。
あくまで、デプロイ対象を先に作っておくことがポイントになります。Hollow JARの場合は微妙ですが。
wildfly-jar:run
をこの前提で書こうとすると、けっこう長くなります…。
$ mvn package wildfly-jar:package wildfly-jar:run
設定を行う
Bootable JARとして構成されるWildFlyの設定を変更する方法はいくつかありますが、基本はパッケージング時でしょうね。
WildFly CLIのスクリプトを使って設定することになります。
Configuring the server during packaging
今回は、扱いません…。
コンポーネントをカスタマイズする
次に、利用するコンポーネントをカスタマイズしてみましょう。
Composing custom server with Galleon layers
ここで出てくるGalleonというのは、複数のコンポーネントで構成されるソフトウェアを作成、プロビジョニングするための
ツールです。
要するに、WildFly Bootable JAR Maven Pluginでは、このGalleonを使って利用するコンポーネントを選択することになります。
デフォルトでは、standalone-microprofile.xml
相当の構成でBootable JARが作成されるようです。
Specifying the set of Galleon layers to use
こちらでしょうかね?
コンポーネントの設定を行うには、2つの書き方があるようです。
- Galleon layerを使う
- Galleon feature-packを使う
とはいえ、互いに排他的な関係ではなさそうですが。
ただ、feature-packを使った場合はfeature-pack-location
を使ったWildFlyのバージョン指定はできなくなり、
これもfeature-packとして指定することになります。
<feature-packs> <feature-pack> <location>wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final</location> </feature-pack> <feature-pack> <groupId>org.wildfly</groupId> <artifactId>wildfly-datasources-galleon-pack</artifactId> <version>1.0.6.Final</version> </feature-pack> </feature-packs>
データソースを扱う場合などは、feature-packを使うことになります。
今回は、Galleon layerのみを使います。
Galleon layerにも2種類あり、基本なlayer(Basic layer)と、その組み合わせで表現されるFoundational layerがあります。
この2つのリストと、先ほどのstandalone-microprofile.xml
に書かれているlayers
の内容を見ると、どのようなlayerが
選択されているのかがわかるでしょう。
<layers> <include name="cloud-server"/> <include name="h2-default-datasource"/> <include name="microprofile-fault-tolerance"/> <include name="microprofile-health"/> <include name="microprofile-jwt"/> <include name="microprofile-metrics"/> <include name="microprofile-openapi"/> <include name="microprofile-opentracing"/> <include name="microprofile-rest-client"/> <include name="undertow-legacy-https"/> <exclude name="management-security-realm"/> </layers>
また、layerは除外することもできます。
今回は、jaxrs-server
とmanagement
を入れておきましょう。
<configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>management</layer> </layers> </configuration>
パッケージングすると
※今回はexecution
の設定は外しています
$ mvn package wildfly-jar:package
最初よりも、10MBほど小さくなりました。
$ ll -h target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT*.* -rw-rw-r-- 1 xxxxx xxxxx 114M 7月 3 20:02 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT-bootable.jar -rw-rw-r-- 1 xxxxx xxxxx 4.9K 7月 3 20:01 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT.war
jaxrs-server
はFoundational layerであり、もう少し削れます。
Basic layerである、jaxrs
とcdi
にしてみましょう。
<configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final</feature-pack-location> <layers> <layer>jaxrs</layer> <layer>cdi</layer> <layer>management</layer> </layers> </configuration>
一気に半分くらいになりました。
$ ll -h target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT*.* -rw-rw-r-- 1 xxxxx xxxxx 64M 7月 3 20:06 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT-bootable.jar -rw-rw-r-- 1 xxxxx xxxxx 4.9K 7月 3 20:06 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT.war
こうやって、必要なコンポーネントを選んで、カスタマイズしていくことができます。
Basic layerには依存もあり、このあたりは自動的に解決してくれます。
ちなみに、management
layerはリモートアクセスでの管理機能を提供するもので、WildFly Bootable JAR Maven Pluginでは
wildfly-jar:shutdown
で使われるので、入れておいた方が良い気がします。
開発で使う
設定は、以下に1度戻します。
<configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>management</layer> </layers> </configuration>
ここからは、開発用途での使い方を書いていきましょう。
JARファイルをスリムにする
ここまで見てきた通り、Bootable JARはそれなりのサイズになります。
実環境では使えなくなるとは思いますが、WildFlyのモジュールをローカルのMavenリポジトリから使用することで、
JARファイルのサイズを小さくすることができます。
Provisioning a slim bootable JAR
plugin-options
として、jboss-maven-dist
を追加します。
<plugin-options> <jboss-maven-dist/> </plugin-options>
configuration
としては、こうなります。
<configuration> <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#24.0.0.Final</feature-pack-location> <layers> <layer>jaxrs-server</layer> <layer>management</layer> </layers> <plugin-options> <jboss-maven-dist/> </plugin-options> </configuration>
これでパッケージングすると
$ mvn package wildfly-jar:package
Bootable JARファイルのサイズが、一気に数Mまで小さくなります。
$ ll -h target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT*.* -rw-rw-r-- 1 xxxxx xxxxx 3.9M 7月 3 20:16 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT-bootable.jar -rw-rw-r-- 1 xxxxx xxxxx 4.9K 7月 3 20:16 target/wildfly-bootable-jar-example-0.0.1-SNAPSHOT.war
パッケージングなどにかかる時間も、短くなります。
ソースコードの監視を使った開発モード
次は、WildFly Bootable JAR Maven Pluginでの、開発中に便利なモードを使っていきましょう。
まずは、ソースコードの監視を使った開発モードです。
Development mode with source watching
使い方は簡単で、以下のコマンドを実行します。
$ mvn wildfly-jar:dev-watch
すると、空のサーバー(Hollow JAR)が起動します。
[INFO] Hollow jar, No application deployment added to server.
あとは、ソースコードの変更を検知すると自動で再コンパイル&デプロイを行い、変更をサーバーに反映してくれます。
target
ディレクトリが空の状態で起動しても、勝手にパッケージング&デプロイします。
$ curl localhost:8080/message Hello World!!
起動後にソースコードを変更すると
@ApplicationScoped public class MessageService { public String message(String word) { return String.format("Hello %s!??", word); } }
変更を検出して再デプロイが行われます。
[INFO] Changes detected - recompiling the module! [INFO] Compiling 3 source files to /path/to/target/classes [INFO] Exploding webapp [INFO] Assembling webapp [wildfly-bootable-jar-example] in [/path/to/target/deployments/ROOT.war] [INFO] Processing war project [INFO] Webapp assembled in [5 msecs] 20:26:16,524 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 9) WFLYUT0022: Unregistered web context: '/' from server 'default-server' 20:26:16,580 INFO [org.jboss.as.server.deployment] (MSC service thread 1-3) WFLYSRV0028: Stopped deployment ROOT.war (runtime-name: ROOT.war) in 62ms 20:26:16,607 INFO [org.jboss.as.server] (management-handler-thread - 1) WFLYSRV0009: Undeployed "ROOT.war" (runtime-name: "ROOT.war") 20:26:16,615 INFO [org.jboss.as.server.deployment] (MSC service thread 1-2) WFLYSRV0027: Starting deployment of "ROOT.war" (runtime-name: "ROOT.war") 20:26:16,699 INFO [org.jboss.weld.deployer] (MSC service thread 1-8) WFLYWELD0003: Processing weld deployment ROOT.war 20:26:17,025 INFO [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 47) RESTEASY002225: Deploying javax.ws.rs.core.Application: class org.littlewings.jakarta.wildfly.bootable.JaxrsActivator 20:26:17,033 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 47) WFLYUT0021: Registered web context: '/' for server 'default-server' 20:26:17,049 INFO [org.jboss.as.server] (management-handler-thread - 1) WFLYSRV0010: Deployed "ROOT.war" (runtime-name : "ROOT.war")
確認。
$ curl localhost:8080/message Hello World!??
なかなか便利ではないでしょうか?
いくつかポイント、注意事項があります。
- サーバーはフォアグラウンドで起動するので、停止はCtrl-cで行う
- WAR、JAR、EARをサポート
src/main/java
(デフォルト)およびsrc/main/webapp
、src/main/resources
の変更を検知して、再デプロイするpom.xml
のWildFly Bootable JAR Maven Pluginの設定変更は、サーバーの再起動が必要pom.xml
のWildFly Bootable JAR Maven Plugin以外の設定変更は、再デプロイが行われる- コンパイルエラーでは停止しない
- マルチモジュールはサポートしていない
- リソースファイルのフィルタリング(include/exclude)はサポートされておらず、すべて監視対象となる
開発モードサーバー+再パッケージング
もうひとつは、先に開発モードのサーバーを起動しておき、パッケージングすると自動で再デプロイする方法です。
Development mode with repackaging
最初に、wildfly-jar:dev
で開発サーバーを起動します。
$ mvn wildfly-jar:dev
こちらもHollow JARです。
[INFO] Hollow jar, No application deployment added to server.
このサーバーはバックグラウンドで起動します。
この状態で-Ddev
を指定してパッケージングを行うと、target/deployments
にファイルが配置、デプロイが行われます。
$ mvn package wildfly-jar:package -Ddev
あとは、ソースコードを変更してから同じように再パッケージングすると、自動でデプロイされます。
$ mvn package wildfly-jar:package -Ddev
wildfly-jar:dev-watch
との違いは、明示的な再パッケージングがデプロイのトリガーになることですね。
なお、開発サーバーはバックグラウンドで起動したままなので、wildfly-jar:shutdown
で停止します。
$ mvn wildfly-jar:shutdown
この時に、management
layerが必要になります。
まとめ
WildFly Bootable JAR Maven Pluginを試してみました。けっこう便利ではないでしょうか?
実際に動かす環境ではWildFlyサーバーにデプロイするようなケースでも、手元では開発モードでBootable JARで動かして確認して、
実際の環境ではデプロイ時はWARファイルで、という使い方も良いのかなと思います。
覚えておきましょう。