最近でてきたフレームワーク、Helidon、Micronaut、Quarkusのクイックスタート、Native-Imageをまとめて試しましょう。
準備
SDKMANインストール
今回はSDKMANで環境を作っていきます。
https://sdkman.io/
コマンドラインで次のコマンドを実行します。Windowsの場合はCygwinかWSLで。
$ curl -s "https://get.sdkman.io" | bash
ターミナルを開きなおすか次のコマンドを実行するとSDKMANが有効になります。
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
JDKインストール
今回はnative-imageまで使うのでGraalVMを使っておきましょう。
$ sdk use java 19.1.0-grl
native-imageの準備も行います。Cygwinではnative-imageはバンドルされているので不要ですが、いまのところ3つのフレームワークのネイティブ化ができてません。
$ gu install native-image
Mavenインストール
HelidonとQuarkusではMavenを使うのでインストールしておきます。
$ sdk install maven
Helidon
HelidonはOracleのWebLogicチームが開発しているフレームワークです。
https://helidon.io/
独自APIを使うSEとMicroProfileを使うMPがありますが、現時点でnative-imageに対応しているのはSEのみなので、ここではSEを使います。
プロジェクト作成
archetypeから作成しますが、いろいろ入力するのは面倒なので、候補から選択します。
$ mvn archetype:generate
たくさん候補がでるので、絞り込みます。
... 2450: remote -> xyz.luan.generator:xyz-gae-generator (-) 2451: remote -> xyz.luan.generator:xyz-generator (-) Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1387:
ここでhelidon
と入力すると2つに絞られます。
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1387: helidon Choose archetype: 1: remote -> io.helidon.archetypes:helidon-quickstart-mp (Quickstart archetype for Helidon MP) 2: remote -> io.helidon.archetypes:helidon-quickstart-se (Quickstart archetype for Helidon SE) Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): :
2
を入力してHelidon SEを選びます。
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 2 Choose io.helidon.archetypes:helidon-quickstart-se version: 1: 0.9.0 ... 16: 1.1.1 17: 1.1.2 Choose a number: 17:
そのままenterをおして最新を選びます。
その後、groupId
、artifactId
、version
、package
を入力します。groupId
は組織名、artifactId
がプロジェクト名です。
Define value for property 'groupId': kis Define value for property 'artifactId': start-helidon Define value for property 'version' 1.0-SNAPSHOT: : Define value for property 'package' kis: : Confirm properties configuration: groupId: kis artifactId: start-helidon version: 1.0-SNAPSHOT package: kis Y: : y
artifactId
と同じ名前のディレクトリができているので移動しておきます。
$ cd start-helidon
ビルド
ビルドはMavenで。
$ mvn package
実行
targetにartifactIdと同じ名前のjarファイルができていて、このjarファイルを実行すればサーバーが起動します。
$ java -jar target/start-helidon.jar [DEBUG] (main) Using Console logging 2019.07.15 07:35:48 INFO io.helidon.webserver.NettyWebServer Thread[main,5,main]: Version: 1.1.2 2019.07.15 07:35:48 INFO io.helidon.webserver.NettyWebServer Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default' started: [id: 0x8985c83f, L:/0:0:0:0:0:0:0:0:8080] WEB server is up! http://localhost:8080/greet
メッセージどおりhttp://localhost:8080/greetにアクセスするとJSONが返ってきます。
ネイティブ化
native-image
プロファイルでMavenビルドするとネイティブ化できます。
$ mvn -Pnative-image package
1分ほど待つと、target
ディレクトリに実行ファイルができます。
$ target/start-helidon 2019.07.15 07:42:14 INFO io.helidon.webserver.NettyWebServer !thread!: Version: 1.1.2 2019.07.15 07:42:14 INFO io.helidon.webserver.NettyWebServer !thread!: Channel '@default' started: [id: 0xb59ae091, L:/0:0:0:0:0:0:0:0:8080] WEB server is up! http://localhost:8080/greet
Micronaut
MicroanutはGrailsを作っていたObject Computing社が開発しているフレームワークです。独自APIを使っていて、APIの使いやすさやドキュメントのわかりやすさが魅力。KotlinやGroovyにも対応しています。
https://micronaut.io/
プロジェクト作成
プロジェクト作成にはMicornautのコマンドを使います。これもSDKMANでインストールできます。
$ sdk install micronaut
mn
コマンドでプロジェクトを生成します。
$ mn create-app start-mn Resolving dependencies.. | Generating Java project... | Application created at /home/naoki/starts/start-mn
プロジェクト名のディレクトリに移動します。
$ cd start-mn
コントローラーは作成されないので、mnコマンドでコントローラーを作成します。
$ mn create-controller MyController
src/main/java/start/mn/MyController.javaが作成されるので少し編集します。
package start.mn; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; @Controller // パスを消しておく public class MyController { @Get(produces="TEXT/PLAIN") // 出力メディアタイプを指定 public String hello() { // 戻り値をStringに return "Hello"; // メッセージを返す } }
ビルド
ビルドはGradleを使います。
$ ./gradlew build > Task :compileJava Note: Creating bean classes for 1 type elements BUILD SUCCESSFUL in 8s 10 actionable tasks: 10 executed
実行
build/libs
に実行可能jarが作成されているので実行するとサーバーが起動します。
$ java -jar build/libs/start-mn-0.1-all.jar 07:57:32.751 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 1496ms. Server Running: http://localhost:8080
http://localhost:8080にアクセスするとメッセージが表示されます。
※ 8/13追記 1.2からstart-mn-0.1.jarじゃなくstart-mn-0.1-all.jarになった?
ネイティブ化
Micronautでは特別なネイティブ化コマンドは用意されていないので、native-image
コマンドを直接使います。
$ native-image -jar build/libs/start-mn-0.1-all.jar
カレントディレクトリに実行ファイルが作成されます。
$ ./start-mn-0.1-all 08:03:09.159 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 131ms. Server Running: http://localhost:8080
Quarkus
QuarkusはRed Hatが開発しているフレームワークで、MicroProfileをベースにしています。
https://quarkus.io/
プロジェクト作成
プロジェクト作成にはMavenを使いますが、通常のarchetypeではなく独自プラグインを使います。
$ mvn io.quarkus:quarkus-maven-plugin::create
groupId
やartifactId
のほかにRESTリソースを作るかきかれるので、y
にしておきます。
$ mvn io.quarkus:quarkus-maven-plugin::create [INFO] Scanning for projects... [INFO] [INFO] ------------------< org.apache.maven:standalone-pom >------------------- [INFO] Building Maven Stub Project (No POM) 1 [INFO] --------------------------------[ pom ]--------------------------------- [INFO] [INFO] --- quarkus-maven-plugin:0.19.1:create (default-cli) @ standalone-pom --- Set the project groupId [org.acme.quarkus.sample]: kis Set the project artifactId [my-quarkus-project]: start-quarkus Set the project version [1.0-SNAPSHOT]: Do you want to create a REST resource? (y/n) [no]: y Set the resource classname [kis.HelloResource]: Set the resource path [/hello]: Creating a new project in /home/naoki/starts/start-quarkus ...
ビルド
ビルドはMavenでいつもどおり
$ mvn package
実行
target
ディレクトリに実行ファイルができるので、javaコマンドで実行することができます。
$ java -jar target/start-quarkus-1.0-SNAPSHOT-runner.jar 2019-07-15 08:25:07,637 INFO [io.quarkus] (main) Quarkus 0.19.1 started in 0.878s. Listening on: http://[::]:8080 2019-07-15 08:25:07,656 INFO [io.quarkus] (main) Installed features: [cdi, resteasy]
http://localhost:8080/hello にアクセスするとメッセージが表示されます。
Quarkusの場合、Mavenで実行することでオートリローディングが有効になるので、開発時はこちらを使うほうが便利です。
$ mvn quarkus:dev
ネイティブ化
Quarkusのネイティブ化は、native
プロファイルを指定してビルドします。
$ mvn -Pnative package
1分ちょい待つとtarget
ディレクトリに実行ファイルができるので、これを実行するとサーバーが起動します。
$ target/start-quarkus-1.0-SNAPSHOT-runner 2019-07-15 08:31:53,378 INFO [io.quarkus] (main) Quarkus 0.19.1 started in 0.016s. Listening on: http://[::]:8080 2019-07-15 08:31:53,379 INFO [io.quarkus] (main) Installed features: [cdi, resteasy]
起動時間やメモリの比較
今回はWSL上のUbuntuでの起動時間と利用メモリを比較してみます。
Helidonでは起動時間が表示されていないので、次のような表示コードを追加しておきます。
System.out.println(ManagementFactory.getRuntimeMXBean().getUptime());
起動時間は次のようになります。
GraalVM JDK | OpenJDK 12.0.1 | native-image | |
---|---|---|---|
Helidon | 864ms | 715ms | 16ms |
Micronaut | 1552ms | 1387ms | 109ms |
Quarkus | 819ms | 720ms | 15ms |
ネイティブ化すると圧倒的に起動が速くなってますが、GraalVMよりもOpenJDK 12のほうがかなり速いですね。GraalとC2の違いだと思います。GraalではJavaで書かれているGraal自体をJITするのに時間がかかるので起動は遅くなりがちです。
メモリ使用量は次のような感じに。
GraalVM JDK | OpenJDK 12.0.1 | native-image | |
---|---|---|---|
Helidon | 233.7MB | 64.9MB | 7.4MB |
Micronaut | 344.6MB | 95.2MB | 15.0MB |
Quarkus | 246.6MB | 81.3MB | 6.9MB |
これもネイティブ化するとメモリ使用量が激減してますが、GraalVMよりもOpenJDK 12のほうが少なくなってます。Graalがメモリを使ってるんですかね。