CLOVER🍀

That was when it all began.

はじめおのQuarkus

これは、なにをしたくお曞いたもの

Quarkusずいう、Red Hatが開発しおいるフレヌムワヌクを、ちょっず詊しおみようず。

Javaフレームワーク「Quarkus」登場。Javaコードからネイティブバイナリを生成し瞬時にJavaアプリが起動、コンテナへの最適化を実現。Red Hatがリリース - Publickey

ネむティブビルドも可胜なフレヌムワヌクずしお、けっこう話題になったむメヌゞがありたす。

そろそろ、詊しおみたいなぁず。

Quarkus

Quarkusに぀いお。

Quarkus - Supersonic Subatomic Java

オフィシャルサむトを芋るず、

  • コンテナファヌスト 
 メモリフットプリントも軜く、Kubernetesのようなコンテナオヌケストレヌション環境に適しおいる
  • 呜什圢のスタむルも、リアクティブも䞡方䜿える
  • デプロむが簡単

ずいったこずが特城ずしお挙げられおいたす。

ずりあえず、Getting Startedを芋ながら詊しおいこうず思いたす。

Quarkus - Get Started

環境

今回の環境は、こちらです。

$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)


$ mvn -version
Apache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-05T04:00:29+09:00)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 1.8.0_191, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-48-generic", arch: "amd64", family: "unix"

利甚するQuarkusのバヌゞョンは、0.14ずしたす。

はじめおのQuakusアプリケヌション

ずりあえず、察象のディレクトリを䜜成。

$ mkdir getting-started
$ cd getting-started

䜜成したディレクトリ内で、Mavenプロゞェクトを䜜成したす。

$ mvn io.quarkus:quarkus-maven-plugin:0.14.0:create \
    -DprojectGroupId=org.littlewings.quarkus \
    -DprojectArtifactId=getting-started

こんな感じのメッセヌゞが出たす。

[INFO] ========================================================================================
[INFO] Your new application has been created in /path/to/getting-started/.
[INFO] Navigate into this directory and launch your application with mvn compile quarkus:dev
[INFO] Your application will be accessible on http://localhost:8080
[INFO] ========================================================================================

プロゞェクト䜜成時に指定できるオプションは、こんな感じです。

Maven Tooling

https://github.com/quarkusio/quarkus/blob/0.14.0/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java#L71-L93

ちなみに、Gettins Startedだず䜜成するJAX-RSリ゜ヌスクラスずパスを指定しおいたすが、今回は省略したした。
指定した堎合は、JAX-RSリ゜ヌスクラスずテストコヌドが䜜成されたす。

生成された、pom.xmlを芋おみたす。
pom.xml

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.littlewings.quarkus</groupId>
  <artifactId>getting-started</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <surefire-plugin.version>2.22.0</surefire-plugin.version>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <quarkus.version>0.14.0</quarkus.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-bom</artifactId>
        <version>${quarkus.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-maven-plugin</artifactId>
        <version>${quarkus.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>build</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <configuration>
          <systemProperties>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
          </systemProperties>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>native</id>
      <activation>
        <property>
          <name>native</name>
        </property>
      </activation>
      <build>
        <plugins>
          <plugin>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-maven-plugin</artifactId>
            <version>${quarkus.version}</version>
            <executions>
              <execution>
                <goals>
                  <goal>native-image</goal>
                </goals>
                <configuration>
                  <enableHttpUrlHandler>true</enableHttpUrlHandler>
                </configuration>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>${surefire-plugin.version}</version>
            <executions>
              <execution>
                <goals>
                  <goal>integration-test</goal>
                  <goal>verify</goal>
                </goals>
                <configuration>
                  <systemProperties>
                    <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
                  </systemProperties>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
</project>

RESTEasyが利甚できそうです。ネむティブむメヌゞのビルドもできそうな蚭定も入っおいたす。

タヌゲットは、Java 8みたいですね。

    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>

生成されたファむル䞀芧。

$ find -type f
./.dockerignore
./.mvn/wrapper/MavenWrapperDownloader.java
./.mvn/wrapper/maven-wrapper.jar
./.mvn/wrapper/maven-wrapper.properties
./pom.xml
./mvnw
./mvnw.cmd
./src/main/docker/Dockerfile.jvm
./src/main/docker/Dockerfile.native
./src/main/resources/META-INF/resources/index.html
./src/main/resources/application.properties

ずりあえず、JAX-RSリ゜ヌスクラスを䜜成しおみたす。
src/main/java/org/littlewings/quarkus/gettingstarted/HelloResource.java

package org.littlewings.quarkus.gettingstarted;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("hello")
public class HelloResource {
    @GET
    @Path("message")
    @Produces(MediaType.TEXT_PLAIN)
    public String message() {
        return "Hello Quarkus!!";
    }
}

mainメ゜ッドを持ったクラスはありたせん。

アプリケヌション䜜成時に指瀺された、Mavenのコマンドを実行しおみたす。

$ mvn compile quarkus:dev

Running the application

起動。ログを芋るず、CDIも䜿えそうですね。

Listening for transport dt_socket at address: 5005
2019-04-29 15:06:19,305 INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
2019-04-29 15:06:19,862 INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 557ms
2019-04-29 15:06:20,048 INFO  [io.quarkus] (main) Quarkus 0.14.0 started in 0.809s. Listening on: http://[::]:8080
2019-04-29 15:06:20,049 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

確認。

$ curl localhost:8080/hello/message
Hello Quarkus!!

動きたした。

アプリケヌションを動かしたたたの状態で、少し゜ヌスコヌドを倉曎しおみたす。

    @GET
    @Path("message")
    @Produces(MediaType.TEXT_PLAIN)
    public String message() {
        return "Hello Quarkus!!??";
    }

curlでアクセスするず、゜ヌスコヌドの倉曎を怜知しお反映しおくれるようです。

2019-04-29 15:07:51,079 INFO  [io.qua.dev] (executor-thread-1) Changed source files detected, recompiling [/path/to/getting-started/src/main/java/org/littlewings/quarkus/gettingstarted/HelloResource.java]
2019-04-29 15:07:51,399 INFO  [io.quarkus] (executor-thread-1) Quarkus stopped in 0.002s
2019-04-29 15:07:51,399 INFO  [io.qua.dep.QuarkusAugmentor] (executor-thread-1) Beginning quarkus augmentation
2019-04-29 15:07:51,506 INFO  [io.qua.dep.QuarkusAugmentor] (executor-thread-1) Quarkus augmentation completed in 107ms
2019-04-29 15:07:51,520 INFO  [io.quarkus] (executor-thread-1) Quarkus 0.14.0 started in 0.121s. Listening on: http://[::]:8080
2019-04-29 15:07:51,520 INFO  [io.quarkus] (executor-thread-1) Installed features: [cdi, resteasy]
2019-04-29 15:07:51,520 INFO  [io.qua.dev] (executor-thread-1) Hot replace total time: 0.442s 

結果。

$ curl localhost:8080/hello/message
Hello Quarkus!!??

ずりあえず、元に戻しおおきたす。

    @GET
    @Path("message")
    @Produces(MediaType.TEXT_PLAIN)
    public String message() {
        return "Hello Quarkus!!";
    }

他に生成されたファむルを芋おみたしょう。

蚭定ファむル。ただ䞭身は無いようです。
src/main/resources/application.properties

# Configuration file
# key = value

HTMLが含たれおいたす。

src/main/resources/META-INF/resources/index.html

どうも、「ようこそ」っぜいペヌゞだなぁず思ったので

<div class="banner lead">
    Your new Cloud-Native application is ready!
</div>

<div class="container">
    <div class="left-column">
        <p class="lead"> Congratulations, you have created a new Quarkus application.</p>

        <h2>Why do you see this?</h2>

        <p>This page is served by Quarkus. The source is in
            <code>src/main/resources/META-INF/resources/index.html</code>.</p>

        <h2>What can I do from here?</h2>

        <p>If not already done, run the application in <em>dev mode</em> using: <code>mvn compile quarkus:dev</code>.
        </p>
        <ul>
            <li>Add REST resources, Servlets, functions and other services in <code>src/main/java</code>.</li>
            <li>Your static assets are located in <code>src/main/resources/META-INF/resources</code>.</li>
            <li>Configure your application in <code>src/main/resources/application.properties</code>.
            </li>
        </ul>

        <h2>How do I get rid of this page?</h2>
        <p>Just delete the <code>src/main/resources/META-INF/resources/index.html</code> file.</p>
    </div>

アクセスしおみるず、やっぱりそんな感じのペヌゞが衚瀺されたした。䞍芁になったら、削陀するペヌゞずなるでしょう。

f:id:Kazuhira:20190429145401p:plain

デバッグしおみる

Quarkusで䜜ったアプリケヌションをデバッグするには、「mvn quarkus:dev」で起動したアプリケヌションにアタッチするこずに
なるようです。

Development Mode

そういえば、起動時にこんな衚瀺も出おいたした。

Listening for transport dt_socket at address: 5005

IntelliJの堎合、メニュヌの「Run」→「Attach to Process...」からアタッチするプロセスを遞択したす。

f:id:Kazuhira:20190429150243p:plain

デバッグできたした、ず。

f:id:Kazuhira:20190429145858p:plain

パッケヌゞングしおみる

続いお、パッケヌゞングしおみたす。

$ mvn package

「-runner」ず぀いたJARファむルを䜿っお起動できたす。
※ちなみに、このJARファむルはUber JARではありたせん

$ java -jar target/getting-started-1.0-SNAPSHOT-runner.jar 
2019-04-29 15:04:22,781 INFO  [io.quarkus] (main) Quarkus 0.14.0 started in 0.583s. Listening on: http://[::]:8080
2019-04-29 15:04:22,799 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

確認。

$ curl localhost:8080/hello/message
Hello Quarkus!!

続いお、Dockerむメヌゞを䜜成しおみたす。

プロゞェクト䜜成時にDockerfileが䜜成されおいるので、この䞭身を芋おみたす。
src/main/docker/Dockerfile.jvm

####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the docker image run:
#
# mvn package
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/getting-started-jvm .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/getting-started-jvm
#
###
FROM fabric8/java-alpine-openjdk8-jre
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV AB_ENABLED=jmx_exporter
COPY target/lib/* /deployments/lib/
COPY target/*-runner.jar /deployments/app.jar
ENTRYPOINT [ "/deployments/run-java.sh" ]

Java 8がベヌスむメヌゞのようです。

パッケヌゞングしたJARファむルを䜜った状態で

$ mvn package

Dockerむメヌゞをビルドしおみたす。

$ docker image build -f src/main/docker/Dockerfile.jvm -t kazuhira/quarkus-getting-started:1.0 .

できあがったDockerむメヌゞを起動。

$ docker container run -it --rm -p 8080:8080 kazuhira/quarkus-getting-started:1.0 
exec java -Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -javaagent:/opt/agent-bond/agent-bond.jar=jmx_exporter{{9779:/opt/agent-bond/jmx_exporter_config.yml}} -XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:+ExitOnOutOfMemoryError -cp . -jar /deployments/app.jar
2019-04-29 06:14:40,736 INFO  [io.quarkus] (main) Quarkus 0.14.0 started in 0.636s. Listening on: http://0.0.0.0:8080
2019-04-29 06:14:40,757 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

確認。

$ curl localhost:8080/hello/message
Hello Quarkus!!

ネむティブむメヌゞを䜜っおみる

続いお、ネむティブむメヌゞを䜜成しおみたす。

Building Native Image Guide

ロヌカルにGraalVMをむンストヌルしおいない堎合

ネむティブむメヌゞのビルドにはGraalVMが必芁になりたすが、GraalVM自䜓のむンストヌルをしおいなくおもネむティブむメヌゞの
ビルドは行うこずはできたすその堎合は、Dockerが必芁になりたす。

ずりあえず、GraalVMは眮いおおいおビルドしおみたしょう。Profileを「native」にしお、「native-image.docker-build」をtrueにしたす。

$ mvn package -Pnative -Dnative-image.docker-build=true

Producing a container

するず、Quarkusのネむティブむメヌゞビルド甚のDockerむメヌゞをダりンロヌドしおきお

Unable to find image 'quay.io/quarkus/centos-quarkus-native-image:graalvm-1.0.0-rc15' locally
graalvm-1.0.0-rc15: Pulling from quarkus/centos-quarkus-native-image

このコンテナ内でビルが始たりたす。

Status: Downloaded newer image for quay.io/quarkus/centos-quarkus-native-image:graalvm-1.0.0-rc15
[getting-started-1.0-SNAPSHOT-runner:6]    classlist:   4,070.13 ms
[getting-started-1.0-SNAPSHOT-runner:6]        (cap):   1,039.38 ms
[getting-started-1.0-SNAPSHOT-runner:6]        setup:   2,459.11 ms
06:18:42,745 INFO  [org.jbo.threads] JBoss Threads version 3.0.0.Alpha4
06:18:43,382 INFO  [org.xnio] XNIO version 3.7.0.Final
06:18:43,479 INFO  [org.xni.nio] XNIO NIO Implementation Version 3.7.0.Final
[getting-started-1.0-SNAPSHOT-runner:6]   (typeflow):  12,833.82 ms
[getting-started-1.0-SNAPSHOT-runner:6]    (objects):  13,022.13 ms
[getting-started-1.0-SNAPSHOT-runner:6]   (features):     770.32 ms
[getting-started-1.0-SNAPSHOT-runner:6]     analysis:  27,357.96 ms
Printing call tree to /project/reports/call_tree_getting-started-1.0-SNAPSHOT-runner_20190429_061911.txt
Printing list of used classes to /project/reports/used_classes_getting-started-1.0-SNAPSHOT-runner_20190429_061913.txt
Printing list of used packages to /project/reports/used_packages_getting-started-1.0-SNAPSHOT-runner_20190429_061913.txt
[getting-started-1.0-SNAPSHOT-runner:6]     universe:     670.15 ms
[getting-started-1.0-SNAPSHOT-runner:6]      (parse):   2,536.38 ms
[getting-started-1.0-SNAPSHOT-runner:6]     (inline):   4,012.46 ms
[getting-started-1.0-SNAPSHOT-runner:6]    (compile):  17,990.18 ms
[getting-started-1.0-SNAPSHOT-runner:6]      compile:  26,063.85 ms
[getting-started-1.0-SNAPSHOT-runner:6]        image:   2,574.95 ms
[getting-started-1.0-SNAPSHOT-runner:6]        write:     682.75 ms
[getting-started-1.0-SNAPSHOT-runner:6]      [total]:  68,396.51 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:27 min
[INFO] Finished at: 2019-04-29T15:19:45+09:00
[INFO] ------------------------------------------------------------------------

いやぁ、さすがに時間がかかりたすねぇ 。

で、ネむティブむメヌゞ甚のDockerfileを䜿っお、Dockerむメヌゞをビルド。

$ docker image build -f src/main/docker/Dockerfile.native -t kazuhira/quarkus-getting-started-native:1.0 .

起動。

$ docker container run -it --rm -p 8080:8080 kazuhira/quarkus-getting-started-native:1.0 
2019-04-29 06:22:32,735 INFO  [io.quarkus] (main) Quarkus 0.14.0 started in 0.003s. Listening on: http://0.0.0.0:8080
2019-04-29 06:22:32,735 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

こちらもOKそうです。

$ curl localhost:8080/hello/message
Hello Quarkus!!

あ、ネむティブむメヌゞ自䜓を芋おいたせんでしたね。targetディレクトリ配䞋に、「-runner」が付䞎されたファむルが
ネむティブむメヌゞです。

$ ./target/getting-started-1.0-SNAPSHOT-runner

ネむティブむメヌゞビルド時のオプションは、こんな感じに出力されたす。

[INFO] [io.quarkus.creator.phase.nativeimage.NativeImagePhase] docker run -v /path/to/getting-started/target:/project:z --rm --user 1000:1000 quay.io/quarkus/centos-quarkus-native-image:graalvm-1.0.0-rc15 -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy$BySpaceAndTime -jar getting-started-1.0-SNAPSHOT-runner.jar -J-Djava.util.concurrent.ForkJoinPool.common.parallelism=1 -H:FallbackThreshold=0 -H:+PrintAnalysisCallTree -H:-AddAllCharsets -H:EnableURLProtocols=http -H:-SpawnIsolates -H:-JNI --no-server -H:-UseServiceLoaderFeature -H:+StackTrace

このオプションを組み立おおいるのは、このあたりですね。

https://github.com/quarkusio/quarkus/blob/0.14.0/core/creator/src/main/java/io/quarkus/creator/phase/nativeimage/NativeImagePhase.java#L352-L490

ベヌスむメヌゞの指定。

https://github.com/quarkusio/quarkus/blob/0.14.0/core/creator/src/main/java/io/quarkus/creator/phase/nativeimage/NativeImagePhase.java#L104

    private String builderImage = "quay.io/quarkus/centos-quarkus-native-image:graalvm-1.0.0-rc15";

で、プロセス実行です、ず。

https://github.com/quarkusio/quarkus/blob/0.14.0/core/creator/src/main/java/io/quarkus/creator/phase/nativeimage/NativeImagePhase.java#L493-L496

ロヌカルにGraalVMをむンストヌルしおいる堎合

ロヌカルにむンストヌルされおいるGraalVMを䜿う堎合は、環境倉数「GRAALVM_HOME」を䜿っおGraalVMのむンストヌル先を
指定したす。
※GraalVM CE 1.0.0 RC15を䜿うべきみたいですが、今回はRC16を䜿いたした 。

$ export GRAALVM_HOME=/usr/local/graalvm-ce
$GRAALVM_HOME/bin/native-image --version
GraalVM Version 1.0.0-rc16 CE

GraalVMのNative Image Maven Pluginを䜿うわけではないので、JAVA_HOMEにGraalVMを蚭定する必芁はありたせん。

https://github.com/quarkusio/quarkus/blob/0.14.0/core/creator/src/main/java/io/quarkus/creator/phase/nativeimage/NativeImagePhase.java#L339-L346

もしくは、Quarkus Maven Pluginのconfigurationに、graalvmHomeずしお蚭定しおも良さそうです。

https://github.com/quarkusio/quarkus/blob/0.14.0/core/creator/src/main/java/io/quarkus/creator/phase/nativeimage/NativeImagePhase.java#L92

ビルド。

$ mvn package -Pnative

するず、ロヌカルのGraalVMを䜿うようになりたした。

[INFO] [io.quarkus.creator.phase.nativeimage.NativeImagePhase] /usr/local/graalvm-ce/bin/native-image -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy$BySpaceAndTime -jar getting-started-1.0-SNAPSHOT-runner.jar -J-Djava.util.concurrent.ForkJoinPool.common.parallelism=1 -H:FallbackThreshold=0 -H:+PrintAnalysisCallTree -H:-AddAllCharsets -H:EnableURLProtocols=http -H:NativeLinkerOption=-no-pie -H:-SpawnIsolates -H:-JNI --no-server -H:-UseServiceLoaderFeature -H:+StackTrace

できあがったJARずネむティブむメヌゞのサむズ比范。

$ ll -h ./target/getting-started-1.0-SNAPSHOT-runner* 
-rwxrwxr-x 1 xxxxx xxxxx 20M  4月 29 15:36 ./target/getting-started-1.0-SNAPSHOT-runner*
-rw-r--r-- 1 xxxxx xxxxx 43K  4月 29 15:36 ./target/getting-started-1.0-SNAPSHOT-runner.jar

「-runner.jar」の方がやたらサむズが小さいです。

これには理由があっお、実はUber JARではなく、䞀緒に䟝存ラむブラリも必芁な圢態になっおいたす。
䟝存するJARファむルは、「target/lib」配䞋にありたす。

$ ll target/lib
合蚈 10204
drwxrwxr-x  2 xxxxx xxxxx    4096  4月 29 17:05 ./
drwxrwxr-x 10 xxxxx xxxxx    4096  4月 29 17:05 ../
-rw-rw-r--  1 xxxxx xxxxx   65690  4月 29 17:05 com.sun.activation.jakarta.activation-1.2.1.jar
-rw-rw-r--  1 xxxxx xxxxx  335042  4月 29 17:05 commons-codec.commons-codec-1.11.jar
-rw-rw-r--  1 xxxxx xxxxx  208700  4月 29 17:05 commons-io.commons-io-2.5.jar
-rw-rw-r--  1 xxxxx xxxxx   61829  4月 29 17:05 commons-logging.commons-logging-1.2.jar
-rw-rw-r--  1 xxxxx xxxxx  113572  4月 29 17:05 io.quarkus.arc.arc-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx   21874  4月 29 17:05 io.quarkus.quarkus-arc-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx  110492  4月 29 17:05 io.quarkus.quarkus-core-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx   16756  4月 29 17:05 io.quarkus.quarkus-jaxb-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx    2549  4月 29 17:05 io.quarkus.quarkus-jsonb-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx    2516  4月 29 17:05 io.quarkus.quarkus-jsonp-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx   17662  4月 29 17:05 io.quarkus.quarkus-resteasy-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx    6123  4月 29 17:05 io.quarkus.quarkus-resteasy-common-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx    2984  4月 29 17:05 io.quarkus.quarkus-resteasy-jsonb-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx   47118  4月 29 17:05 io.quarkus.quarkus-undertow-0.14.0.jar
-rw-rw-r--  1 xxxxx xxxxx   48421  4月 29 17:05 io.smallrye.smallrye-config-1.3.5.jar
-rw-rw-r--  1 xxxxx xxxxx 2263313  4月 29 17:05 io.undertow.undertow-core-2.0.19.Final.jar
-rw-rw-r--  1 xxxxx xxxxx  532073  4月 29 17:05 io.undertow.undertow-servlet-2.0.19.Final.jar
-rw-rw-r--  1 xxxxx xxxxx   26586  4月 29 17:05 javax.annotation.javax.annotation-api-1.3.2.jar
-rw-rw-r--  1 xxxxx xxxxx   73063  4月 29 17:05 javax.el.javax.el-api-3.0.0.jar
-rw-rw-r--  1 xxxxx xxxxx  107519  4月 29 17:05 javax.enterprise.cdi-api-2.0.SP1.jar
-rw-rw-r--  1 xxxxx xxxxx    2497  4月 29 17:05 javax.inject.javax.inject-1.jar
-rw-rw-r--  1 xxxxx xxxxx   24404  4月 29 17:05 javax.interceptor.javax.interceptor-api-1.2.jar
-rw-rw-r--  1 xxxxx xxxxx   23665  4月 29 17:05 javax.json.bind.javax.json.bind-api-1.0.jar
-rw-rw-r--  1 xxxxx xxxxx   93107  4月 29 17:05 javax.validation.validation-api-2.0.1.Final.jar
-rw-rw-r--  1 xxxxx xxxxx  128076  4月 29 17:05 javax.xml.bind.jaxb-api-2.3.1.jar
-rw-rw-r--  1 xxxxx xxxxx    2254  4月 29 17:05 net.jcip.jcip-annotations-1.0.jar
-rw-rw-r--  1 xxxxx xxxxx  767916  4月 29 17:05 org.apache.httpcomponents.httpclient-4.5.7.jar
-rw-rw-r--  1 xxxxx xxxxx  326874  4月 29 17:05 org.apache.httpcomponents.httpcore-4.4.11.jar
-rw-rw-r--  1 xxxxx xxxxx   16772  4月 29 17:05 org.eclipse.microprofile.config.microprofile-config-api-1.3.jar
-rw-rw-r--  1 xxxxx xxxxx  313516  4月 29 17:05 org.eclipse.yasson-1.0.3.jar
-rw-rw-r--  1 xxxxx xxxxx  128770  4月 29 17:05 org.glassfish.javax.json-1.1.4.jar
-rw-rw-r--  1 xxxxx xxxxx  430053  4月 29 17:05 org.graalvm.sdk.graal-sdk-1.0.0-rc15.jar
-rw-rw-r--  1 xxxxx xxxxx   66469  4月 29 17:05 org.jboss.logging.jboss-logging-3.3.2.Final.jar
-rw-rw-r--  1 xxxxx xxxxx   20593  4月 29 17:05 org.jboss.logging.jboss-logging-annotations-2.1.0.Final.jar
-rw-rw-r--  1 xxxxx xxxxx  257131  4月 29 17:05 org.jboss.logmanager.jboss-logmanager-embedded-1.0.3.jar
-rw-rw-r--  1 xxxxx xxxxx  706440  4月 29 17:05 org.jboss.resteasy.resteasy-core-4.0.0.CR2.jar
-rw-rw-r--  1 xxxxx xxxxx  171097  4月 29 17:05 org.jboss.resteasy.resteasy-core-spi-4.0.0.CR2.jar
-rw-rw-r--  1 xxxxx xxxxx   15733  4月 29 17:05 org.jboss.resteasy.resteasy-json-binding-provider-4.0.0.CR2.jar
-rw-rw-r--  1 xxxxx xxxxx   13019  4月 29 17:05 org.jboss.resteasy.resteasy-json-p-provider-4.0.0.CR2.jar
-rw-rw-r--  1 xxxxx xxxxx    9977  4月 29 17:05 org.jboss.slf4j.slf4j-jboss-logging-1.1.0.Final.jar
-rw-rw-r--  1 xxxxx xxxxx  300862  4月 29 17:05 org.jboss.spec.javax.servlet.jboss-servlet-api_4.0_spec-1.0.0.Final.jar
-rw-rw-r--  1 xxxxx xxxxx  144090  4月 29 17:05 org.jboss.spec.javax.ws.rs.jboss-jaxrs-api_2.1_spec-1.0.2.Final.jar
-rw-rw-r--  1 xxxxx xxxxx  131532  4月 29 17:05 org.jboss.spec.javax.xml.bind.jboss-jaxb-api_2.3_spec-1.0.1.Final.jar
-rw-rw-r--  1 xxxxx xxxxx   94766  4月 29 17:05 org.jboss.threads.jboss-threads-3.0.0.Alpha4.jar
-rw-rw-r--  1 xxxxx xxxxx  585290  4月 29 17:05 org.jboss.xnio.xnio-api-3.7.0.Final.jar
-rw-rw-r--  1 xxxxx xxxxx  121458  4月 29 17:05 org.jboss.xnio.xnio-nio-3.7.0.Final.jar
-rw-rw-r--  1 xxxxx xxxxx   14769  4月 29 17:05 org.osgi.org.osgi.annotation.versioning-1.0.0.jar
-rw-rw-r--  1 xxxxx xxxxx    2097  4月 29 17:05 org.reactivestreams.reactive-streams-1.0.2.jar
-rw-rw-r--  1 xxxxx xxxxx   41203  4月 29 17:05 org.slf4j.slf4j-api-1.7.25.jar
-rw-rw-r--  1 xxxxx xxxxx  306888  4月 29 17:05 org.wildfly.common.wildfly-common-1.5.0.Final-format-001.jar
-rw-rw-r--  1 xxxxx xxxxx   37911  4月 29 17:05 org.wildfly.security.wildfly-elytron-asn1-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx   12632  4月 29 17:05 org.wildfly.security.wildfly-elytron-auth-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx  255834  4月 29 17:05 org.wildfly.security.wildfly-elytron-auth-server-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx   45306  4月 29 17:05 org.wildfly.security.wildfly-elytron-base-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx  259181  4月 29 17:05 org.wildfly.security.wildfly-elytron-credential-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx   63438  4月 29 17:05 org.wildfly.security.wildfly-elytron-permission-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx  160200  4月 29 17:05 org.wildfly.security.wildfly-elytron-ssl-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx   41636  4月 29 17:05 org.wildfly.security.wildfly-elytron-util-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx   36464  4月 29 17:05 org.wildfly.security.wildfly-elytron-x500-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx   72291  4月 29 17:05 org.wildfly.security.wildfly-elytron-x500-cert-2.0.0.Alpha1.jar
-rw-rw-r--  1 xxxxx xxxxx    7998  4月 29 17:05 org.wildfly.security.wildfly-elytron-x500-cert-util-2.0.0.Alpha1.jar

これをUber JARにするには、Quarkus Maven Pluginの蚭定で、「uberJar」をtrueにする必芁がありたす。

  <build>
    <plugins>
      <plugin>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-maven-plugin</artifactId>
        <version>${quarkus.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>build</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <uberJar>true</uberJar>
        </configuration>
      </plugin>

Uber-Jar Creation

パッケヌゞングしなおすず、10M近くになりたした。

-rw-r--r-- 1 xxxxx xxxxx 9.5M  4月 29 17:07 getting-started-1.0-SNAPSHOT-runner.jar

単玔な比范だずネむティブむメヌゞの方が倧きいんですけど、Java自䜓のランタむムのサむズを考えるず、この差が軜くひっくり
返りたすね 。

CDIも足しおみる

せっかくなので、もう少し凊理を足しおみたしょう。

ずりあえず、アプリケヌションは起動したたたにしたす。

$ mvn compile quarkus:dev

こんなクラスを䜜り、
src/main/java/org/littlewings/quarkus/gettingstarted/CalcService.java

package org.littlewings.quarkus.gettingstarted;

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class CalcService {
    public int add(int a, int b) {
        return a + b;
    }
}

JAX-RSリ゜ヌスクラスは、゚ンドポむントを远加。
src/main/java/org/littlewings/quarkus/gettingstarted/HelloResource.java

package org.littlewings.quarkus.gettingstarted;

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.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("hello")
@ApplicationScoped
public class HelloResource {
    @Inject
    CalcService calcService;

    @GET
    @Path("message")
    @Produces(MediaType.TEXT_PLAIN)
    public String message() {
        return "Hello Quarkus!!";
    }

    @GET
    @Path("add")
    @Produces(MediaType.TEXT_PLAIN)
    public int add(@QueryParam("a") int a, @QueryParam("b") int b) {
        return calcService.add(a, b);
    }
}

特に再起動などしないたた、倉曎が反映されたした。

$ curl 'localhost:8080/hello/add?a=5&b=3'
8

すごいですね。

リク゚ストずレスポンスにJSONを䜿っおみる

pom.xmlに、RESTEasy JSON-B Extensionを远加したす。

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jsonb</artifactId>
    </dependency>

起動。

$ mvn compile quarkus:dev

JAX-RSクラスに、以䞋のようなメ゜ッドを远加しお

    @POST
    @Path("add")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.TEXT_PLAIN)
    public Map<String, ?> add(Map<String, Integer> request) {
        Map<String, Integer> result = new HashMap<>();
        result.put("result", calcService.add(request.get("a"), request.get("b")));
        return result;
    }

確認。

$ curl -XPOST -H 'Content-Type: application/json' localhost:8080/hello/add -d '{"a": 5, "b": 3}'
{result=8}

ずりあえず、最初はこんな感じで。

オマケプロゞェクト䜜成時に、JAX-RSリ゜ヌスクラスを指定しおいたら

$ mvn io.quarkus:quarkus-maven-plugin:0.14.0:create \
    -DprojectGroupId=org.littlewings.quarkus \
    -DprojectArtifactId=getting-started \
    -DclassName="org.littlewings.quarkus.gettingstarted.HelloResource" \
    -Dpath="/hello"
$ find -type f
./.dockerignore
./.mvn/wrapper/MavenWrapperDownloader.java
./.mvn/wrapper/maven-wrapper.jar
./.mvn/wrapper/maven-wrapper.properties
./pom.xml
./mvnw
./mvnw.cmd
./src/main/docker/Dockerfile.jvm
./src/main/docker/Dockerfile.native
./src/main/resources/META-INF/resources/index.html
./src/main/resources/application.properties
./src/main/java/org/littlewings/quarkus/gettingstarted/HelloResource.java
./src/test/java/org/littlewings/quarkus/gettingstarted/HelloResourceTest.java
./src/test/java/org/littlewings/quarkus/gettingstarted/NativeHelloResourceIT.java

䜜成された、JAX-RSリ゜ヌスクラス。
src/main/java/org/littlewings/quarkus/gettingstarted/HelloResource.java

package org.littlewings.quarkus.gettingstarted;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class HelloResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
}

この堎合、テストも出力されたす。
src/test/java/org/littlewings/quarkus/gettingstarted/HelloResourceTest.java

package org.littlewings.quarkus.gettingstarted;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class HelloResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("hello"));
    }

}

ネむティブむメヌゞ甚のテストも出力されたすが、こちらは通垞のテストを継承したものですね。
src/test/java/org/littlewings/quarkus/gettingstarted/NativeHelloResourceIT.java

package org.littlewings.quarkus.gettingstarted;

import io.quarkus.test.junit.SubstrateTest;

@SubstrateTest
public class NativeHelloResourceIT extends HelloResourceTest {

    // Execute the same tests but in native mode.
}

ネむティブむメヌゞ甚のテストはむンテグレヌションテストずしお動䜜するので、以䞋のようにしお実行したす。
※環境倉数GRAALVM_HOMEを䜿う堎合

$ mvn -Pnative integration-test
$ mvn -Pnative verify

ビルドプロセスにネむティブむメヌゞのビルドが入るので、それなりに時間はかかりたす 。