Java Quarkus Webサービスで Hello World する
こんにちは、@studio_meowtoon です。今回は、WSL の Ubuntu 22.04 で Java Quarkus Web アプリケーションを作成して Hello World を出力する方法を紹介します。
目的
Windows 11 の Linux でクラウド開発します。
こちらから記事の一覧がご覧いただけます。
実現すること
ローカル環境の Ubuntu で、Java Quarkus Web サービスの JAR ファイル形式、また、ネイティブイメージ形式のアプリを起動します。
① JAR ファイル形式のアプリを起動
要素 | 概要 |
---|---|
terminal | ターミナル |
Ubuntu | OS |
JVM | Java 実行環境 |
app-runner.jar | Java アプリケーション |
netty | Web サーバー |
② ネイティブイメージ形式のアプリを起動
要素 | 概要 |
---|---|
terminal | ターミナル |
Ubuntu | OS |
app-runner | ネイティブイメージ アプリケーション |
netty | Web サーバー |
技術トピック
Quarkus とは?
こちらを展開してご覧いただけます。
Quarkus (クォーカス)
Quarkus は、Java アプリケーションを高速で軽量なマイクロサービスやクラウドネイティブアプリケーションとして実行するためのフレームワークです。
キーワード | 内容 |
---|---|
オープンソース | Quarkus はオープンソースであり、活発なコミュニティによってサポートされています。 |
クラウドネイティブ | Kubernetes などのコンテナ環境との統合が簡単であり、クラウドネイティブアプリケーションの開発を容易にします。 |
マイクロサービス | 小規模で疎結合なマイクロサービスアーキテクチャの開発に適しています。 |
軽量で高速 | Quarkus は GraalVM によるネイティブイメージ生成をサポートし、高速で起動時間が短いアプリケーションを実現します。 |
低メモリ使用量 | 小さなコンテナサイズや省エネルギーな環境に適しています。 |
Java におけるネイティブイメージビルドとは?
こちらを展開してご覧いただけます。
キーワード | 内容 |
---|---|
ネイティブイメージビルド | Java コードをネイティブマシンコードにコンパイルすることです。通常、Java コードは Java バイトコードと呼ばれる中間言語にコンパイルされ、Java 仮想マシン (JVM) で実行されます。しかし、ネイティブイメージビルドは、Java コードを JVM を介さずに直接実行可能なネイティブマシンコードに変換することで、より高速な実行速度とより低いメモリ使用量を実現することができます。 |
ネイティブイメージビルドは、以下のようなニーズから求められています。
キーワード | 内容 |
---|---|
パフォーマンスの向上 | Java は一般的に高水準のプログラミング言語であり、JVM によって実行されるため、実行速度が遅いとされることがあります。ネイティブイメージビルドにより、高速な実行速度を実現することができます。 |
メモリの最適化 | JVM による Java コードの実行には、多くのメモリが必要となることがあります。ネイティブイメージビルドにより、より少ないメモリ使用量でプログラムを実行できるようになります。 |
ネイティブプログラムの統合 | Java は、C言語や C++ などの他のプログラミング言語で書かれたネイティブプログラムと統合することができます。しかし、統合するためには、ネイティブコードが必要になります。ネイティブイメージビルドにより、これらのネイティブプログラムと Java コードをシームレスに統合することができます。 |
開発環境
- Windows 11 Home 22H2 を使用しています。
WSL の Ubuntu を操作していきますので macOS の方も参考にして頂けます。
WSL (Microsoft Store アプリ版) ※ こちらの関連記事からインストール方法をご確認いただけます
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
Ubuntu ※ こちらの関連記事からインストール方法をご確認いただけます
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Java JDK ※ こちらの関連記事からインストール方法をご確認いただけます
$ java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)
Maven ※ こちらの関連記事からインストール方法をご確認いただけます
$ mvn -version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.18, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
この記事では基本的に Ubuntu のターミナルで操作を行います。Vim を使用してコピペする方法を初めて学ぶ人のために、以下の記事で手順を紹介しています。ぜひ挑戦してみてください。
作成する Web アプリケーションの仕様
No | エンドポイント | HTTPメソッド | MIME タイプ |
---|---|---|---|
1 | /api/data | GET | application/json |
説明を開きます。
/api/data というエンドポイントに対して HTTP GET リクエストを送信すると、JSON データがレスポンスされるシンプルな Web サービスを実装します。
Hello World を表示する手順
プロジェクトの作成
プロジェクトフォルダを作成します。
※ ~/tmp/hello-quarkus をプロジェクトフォルダとします。
$ mkdir -p ~/tmp/hello-quarkus
$ cd ~/tmp/hello-quarkus
リソースクラスの作成
リソースクラスを作成します。
$ mkdir -p src/main/java/com/example/quarkus
$ vim src/main/java/com/example/quarkus/HelloResource.java
ファイルの内容
package com.example.quarkus;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/api")
public class HelloResource {
@GET
@Path("/data")
@Produces(MediaType.APPLICATION_JSON)
public Map<String, String> getData() {
Map<String, String> map = Map.of("message", "Hello World!");
return map;
}
}
pom.xml の作成
pom.xml ファイルを作成します。
$ vim 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hello-quarkus</artifactId>
<version>1.0</version>
<name>hello-quarkus</name>
<properties>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>2.16.8.Final</quarkus.platform.version>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
ディレクトリ・ファイル構成
プロジェクトのファイル構成を表示してみます。
$ tree
.
├── pom.xml
└── src
└── main
└── java
└── com
└── example
└── quarkus
└── HelloResource.java
開発モードでアプリを起動
開発モードでアプリを起動します。
※ アプリを停止するときは ctrl + C を押します。
$ mvn quarkus:dev
出力
Listening for transport dt_socket at address: 5005
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-07-31 15:35:11,682 INFO [io.quarkus] (Quarkus Main Thread) hello-quarkus 1.0 on JVM (powered by Quarkus 2.16.8.Final) started in 1.451s. Listening on: http://0.0.0.0:8080
2023-07-31 15:35:11,687 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2023-07-31 15:35:11,688 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]
--
Tests paused
Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
ここまでの手順で、Quarkus アプリを開発モードで起動することができました。
アプリの動作確認
別ターミナルから curl コマンドで確認します。
$ curl -v http://localhost:8080/api/data -w '\n'
出力
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/data HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-length: 22
< Content-Type: application/json;charset=UTF-8
<
* Connection #0 to host localhost left intact
{message=Hello World!}
ここまでの手順で、ターミナルに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。
jar ファイルのビルド
アプリのビルド
Java アプリをビルドします。
※ target/app-runner.jar が作成されます。
$ mvn clean package \
-Dquarkus.package.type=uber-jar
実行します。
$ java -jar target/app-runner.jar
ここまでの手順で、Quarkus アプリの JAR ファイルをビルド・起動することができました。
ネイティブイメージをビルド
pom.xml の修正
pom.xml ファイルを修正します。
$ vim 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hello-quarkus</artifactId>
<version>1.0</version>
<name>hello-quarkus</name>
<properties>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>2.16.8.Final</quarkus.platform.version>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<surefire-plugin.version>3.0.0-M7</surefire-plugin.version>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
ファイルの内容 ※一部抜粋
</project>
<!--省略-->
<properties>
<!--省略-->
<surefire-plugin.version>3.0.0-M7</surefire-plugin.version>
<!--省略-->
</properties>
<!--省略-->
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Docker デーモンを起動します。
$ sudo service docker start
* Starting Docker: docker [ OK ]
Docker 環境をお持ちでない場合は、以下の関連記事から Docker Engine のインストール手順をご確認いただけます。
GraalVM はビルド時に Docker コンテナとして提供されます。
ネイティブイメージをビルドします。
※ target/app-runner ネイティブイメージが作成されます。
$ mvn clean package -Pnative
実行します。
$ ./target/app-runner
ここまでの手順で、Quarkus アプリの ネイティブイメージをビルド・起動することができました。
アプリ起動時間の比較
ファイル形式 | 実行ファイル | 起動時間(秒) |
---|---|---|
JAR ファイル形式 | app-runner.jar | 0.642秒 |
ネイティブイメージ形式 | app-runner | 0.017秒 |
JVM で動作する Quarkus アプリの起動時間も十分速いですが、ネイティブイメージだと起動時間が非常に速いとわかりました。
まとめ
Ubuntu に構築したシンプルな Java 開発環境で、Java Quarkus Web サービスを実行することができました。
実際の業務での Quarkus の使用ケースでは、構成ファイルなどが追加されるため、ここで示したようなシンプルな構成とは異なる場合があります。しかしながら、最小構成の例を学ぶことで、Quarkus がどのような構成が必要なのかを理解することができます。
どうでしたか? WSL Ubuntu で、Java Quarkus Web アプリケーション開発環境を手軽に構築することができます。ぜひお試しください。今後も Java の開発環境などを紹介していきますので、ぜひお楽しみにしてください。
推奨コンテンツ
関連記事
Java JAX-RS
Java Spring Boot