What's?
TIS Advent Calendar 2021に参加ということで。
2年ほど前にMicronaut 1.0で遊んでいたことがあるのですが、気づくと3.0を超えていたので、この機会に久しぶりに触ってみようかなと。
Micronautとは、フルスタックのマイクロサービスやサーバーレスに向くと謳われているフレームワークです。
環境
今回の環境はこちらです。
$ 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.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
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-91-generic", arch: "amd64", family: "unix"
CLIのインストールとプロジェクトの作成
まずは、MicronautのCLIをインストールします。
SDKMANを使って行います。
$ sdk install micronaut
現在のMicronautのバージョンは、3.2.0です。
$ mn --version
Micronaut Version: 3.2.0
そのまま続けて、プロジェクトを作成します。ビルドツールは、Mavenにしました。
$ mn create-app hello-micronaut3 --build maven
プロジェクト内に移動。
$ cd hello-micronaut3
こんな感じの構成になっています。
$ tree
.
├── README.md
├── micronaut-cli.yml
├── mvnw
├── mvnw.bat
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── hello
│ │ └── micronaut3
│ │ └── Application.java
│ └── resources
│ ├── application.yml
│ └── logback.xml
└── test
└── java
└── hello
└── micronaut3
└── HelloMicronaut3Test.java
10 directories, 9 files
含まれているJavaソースコードと
package hello.micronaut3;
import io.micronaut.runtime.Micronaut;
public class Application {
public static void main(String[] args) {
Micronaut.run(Application.class, args);
}
}
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>hello.micronaut3</groupId>
<artifactId>hello-micronaut3</artifactId>
<version>0.1</version>
<packaging>${packaging}</packaging>
<parent>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-parent</artifactId>
<version>3.2.0</version>
</parent>
<properties>
<packaging>jar</packaging>
<jdk.version>11</jdk.version>
<release.version>11</release.version>
<micronaut.version>3.2.0</micronaut.version>
<exec.mainClass>hello.micronaut3.Application</exec.mainClass>
<micronaut.runtime>netty</micronaut.runtime>
</properties>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-validation</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micronaut.test</groupId>
<artifactId>micronaut-test-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-client</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-server-netty</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-runtime</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.micronaut.build</groupId>
<artifactId>micronaut-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- Uncomment to enable incremental compilation -->
<!-- <useIncrementalCompilation>false</useIncrementalCompilation> -->
<annotationProcessorPaths combine.children="append">
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-validation</artifactId>
<version>${micronaut.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Amicronaut.processing.group=hello.micronaut3</arg>
<arg>-Amicronaut.processing.module=hello-micronaut3</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
アプリケーションを書いてみる
こちらを見ながら、簡単なアプリケーションを作ってみましょう。
DIも使っておきます。
Controllerの作成。
package hello.micronaut3;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import jakarta.inject.Inject;
@Controller("/hello")
public class HelloController {
@Inject
MessageService messageService;
@Get(produces = MediaType.TEXT_PLAIN)
public String index() {
return messageService.get();
}
}
Beanの作成。
package hello.micronaut3;
import jakarta.inject.Singleton;
@Singleton
public class MessageService {
public String get() {
return "Hello Micronaut 3!!";
}
}
Micronaut Maven Pluginで起動。
$ mvn mn:run
こんな感じのバナーが表示されます。
__ __ _ _
| \/ (_) ___ _ __ ___ _ __ __ _ _ _| |_
| |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __|
| | | | | (__| | | (_) | | | | (_| | |_| | |_
|_| |_|_|\___|_| \___/|_| |_|\__,_|\__,_|\__|
Micronaut (v3.2.0)
17:13:26.550 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 974ms. Server Running: http://localhost:8080
確認。
$ curl localhost:8080/hello
Hello Micronaut 3!!
OKですね。
次は、パッケージングしてJARファイルを作成しましょう。
$ mvn package
起動。
$ java -jar target/hello-micronaut3-0.1.jar
__ __ _ _
| \/ (_) ___ _ __ ___ _ __ __ _ _ _| |_
| |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __|
| | | | | (__| | | (_) | | | | (_| | |_| | |_
|_| |_|_|\___|_| \___/|_| |_|\__,_|\__,_|\__|
Micronaut (v3.2.0)
17:14:18.344 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 957ms. Server Running: http://localhost:8080
っていうか、起動速いですね。
Startup completed in 957ms.
結果は同じなので、割愛。
ネイティブイメージを作成する
最後に、このアプリケーションをネイティブイメージにしたいと思います。
Microservices as GraalVM native images
GraalVMをインストールせずにDockerを使ってビルドする方法もあるようですが、今回はGraalVMをインストールしてビルドすることにします。
GraalVMもSDKMANでインストール。native-image
ツールもインストールしておきます。
$ sdk install java 21.3.0.r11-grl
$ sdk install java 21.3.0.r11-grl
$ gu install native-image
GraalVMとnative-image
ツールがインストールされました。
$ java --version
openjdk 11.0.13 2021-10-19
OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 11.0.13+7-jvmci-21.3-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.3.0 (build 11.0.13+7-jvmci-21.3-b05, mixed mode, sharing)
$ native-image --version
GraalVM 21.3.0 Java 11 CE (Java Version 11.0.13+7-jvmci-21.3-b05)
-Dpackaging=native-image
を指定して、パッケージング。
$ mvn package -Dpackaging=native-image
だいぶ時間がかかりますが、なんとか完了します。
[hello-micronaut3:208224] classlist: 4,339.55 ms, 0.96 GB
[hello-micronaut3:208224] (cap): 802.08 ms, 0.96 GB
[hello-micronaut3:208224] setup: 3,730.72 ms, 0.96 GB
Warning: class initialization of class io.micronaut.http.server.$CoroutineHelper$Definition failed with exception java.lang.NoClassDefFoundError: kotlin/coroutines/CoroutineContext. This class will be initialized at run time because option --allow-incomplete-classpath is used for image building. Use the option --initialize-at-run-time=io.micronaut.http.server.$CoroutineHelper$Definition to explicitly request delayed initialization of this class.
[hello-micronaut3:208224] (clinit): 2,268.13 ms, 3.58 GB
[hello-micronaut3:208224] (typeflow): 15,282.40 ms, 3.58 GB
[hello-micronaut3:208224] (objects): 140,670.17 ms, 3.58 GB
[hello-micronaut3:208224] (features): 25,422.79 ms, 3.58 GB
[hello-micronaut3:208224] analysis: 192,424.77 ms, 3.58 GB
[hello-micronaut3:208224] universe: 20,954.42 ms, 3.58 GB
[hello-micronaut3:208224] (parse): 5,223.66 ms, 3.61 GB
[hello-micronaut3:208224] (inline): 18,816.18 ms, 3.48 GB
[hello-micronaut3:208224] (compile): 99,596.81 ms, 3.71 GB
[hello-micronaut3:208224] compile: 141,904.16 ms, 3.71 GB
[hello-micronaut3:208224] image: 15,093.41 ms, 3.71 GB
[hello-micronaut3:208224] write: 3,054.96 ms, 3.71 GB
[hello-micronaut3:208224] [total]: 382,040.97 ms, 3.71 GB
# Printing build artifacts to: /path/to/target/hello-micronaut3.build_artifacts.txt
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 06:27 min
[INFO] Finished at: 2021-12-03T17:21:50+09:00
[INFO] ------------------------------------------------------------------------
ネイティブイメージができあがりました。
$ file target/hello-micronaut3
target/hello-micronaut3: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ceca748796f73559894e78c43bb90f0de66038a1, for GNU/Linux 3.2.0, with debug_info, not stripped
起動。
$ ./target/hello-micronaut3
__ __ _ _
| \/ (_) ___ _ __ ___ _ __ __ _ _ _| |_
| |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __|
| | | | | (__| | | (_) | | | | (_| | |_| | |_
|_| |_|_|\___|_| \___/|_| |_|\__,_|\__,_|\__|
Micronaut (v3.2.0)
17:22:42.238 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 63ms. Server Running: http://localhost:8080
起動速度がめちゃくちゃ速くなりました。
Startup completed in 63ms.
動作確認。
$ curl localhost:8080/hello
Hello Micronaut 3!!
補足
GraalVMをインストールせずとも、Dockerを使うとネイティブイメージを作れるようです。
$ mvn package -Dpackaging=docker-native -Pgraalvm
この場合、GraalVMのアーティファクトをダウンロードしてきます。
[INFO] ---------------------------[ docker-native ]----------------------------
Downloading from central: https://repo.maven.apache.org/maven2/org/graalvm/sdk/graal-sdk/21.3.0/graal-sdk-21.3.0.pom
Downloaded from central: https://repo.maven.apache.org/maven2/org/graalvm/sdk/graal-sdk/21.3.0/graal-sdk-21.3.0.pom (1.4 kB at 340 B/s)
Downloading from central: https://repo.maven.apache.org/maven2/org/graalvm/nativeimage/svm/21.3.0/svm-21.3.0.pom
Downloaded from central: https://repo.maven.apache.org/maven2/org/graalvm/nativeimage/svm/21.3.0/svm-21.3.0.pom (1.9 kB at 8.3 kB/s)
...
こんなディレクトリツリーになります。
$ tree $HOME/.m2/repository/org/graalvm -d
$HOME/.m2/repository/org/graalvm
├── buildtools
│ ├── junit-platform-native
│ │ └── 0.9.7.1
│ ├── native-maven-plugin
│ │ └── 0.9.7.1
│ └── utils
│ └── 0.9.7.1
├── compiler
│ └── compiler
│ └── 21.3.0
├── nativeimage
│ ├── objectfile
│ │ └── 21.3.0
│ ├── pointsto
│ │ └── 21.3.0
│ └── svm
│ └── 21.3.0
├── sdk
│ └── graal-sdk
│ └── 21.3.0
└── truffle
└── truffle-api
└── 21.3.0
23 directories
が、手元の環境の事情で、Dockerイメージを使ってビルドする最中に失敗してしまうので…。
回避方法はまた別途探そうかなと思います。
こんなところで?