Spring Boot ApplicationをMicronaut for Springでnative-imageにしてみる

# はじめに
Spring Bootの起動速度のとにかく速めたいな、と思い　[Micronaut for Spring](https://micronaut-projects.github.io/micronaut-spring/latest/guide/index.html) を試してみた結果です。
もし、間違っている部分があればご指摘していただけると嬉しいです。

# 結果

Spring Bootのアプリケーションを、native-imageするのはまだ早い。
でも、何か今後行けそうな夢が見れた。

ソースは全て下記リポジトリの `micronaut-maven` ブランチです。`micronaut-gradle`は、gradle用です。
https://github.com/h-r-k-matsumoto/spring-boot-sample

# 調査したこと

## Spring Framwork 5.1: Support for Graal native image 
Spring Frameworkは、5.1の[wiki](https://github.com/spring-projects/spring-framework/wiki/What's-New-in-Spring-Framework-5.x)に下記のように書いています。

> Support for Graal native image constraints (reflection, parameter names).

もしかして、何もせずともnativeimage作れる？と思いましたが、できませんでした。
https://jira.spring.io/browse/SPR-16991
にある通り、GraalVM側での対応も行って上で、さらにSpring Framework側の対応が必要という事なのでしょう。
ただ、下記のようにDIの設定を `app.json` のように書き出せば・・・動くのかもしれません。

https://github.com/dsyer/spring-boot-aot

## Micronaut for Spring
https://github.com/micronaut-projects/micronaut-spring
https://micronaut-projects.github.io/micronaut-spring/latest/guide/index.html

簡単にいうと、Spring ApplicationをMicronaut Appkicationとして実行できるよ！というものです。

お？これはもしかしてSpring BootからMicronautへの移行なども考慮してスムーズに行えるのでは！？
と試してみました。

# Micronaut for Spring：既存のSpring Bootアプリケーションを変更する

今回以前作成した簡単なSpring Bootアプリケーションを使いました。

https://github.com/h-r-k-matsumoto/spring-boot-sample

## 変更すること

### 依存関係の追加。

micronaut、micronaut-for-spring、graalvm関連のライブラリを追加する必要があります。
詳細は、下記をみてください。
https://github.com/h-r-k-matsumoto/spring-boot-sample/blob/micronaut-maven/pom.xml#L46-L105


### fatJarの作り方の変更

`spring-boot-maven-plugin` で作成されたfatJarは対応されていません。
というよりも、 `org.springframework.boot.loader.JarLauncher` でしか読み込めない形式なので、一般的なjarにする必要があります。

maven-shade-pluginを使い、単純なjar形式に全てのクラスを含めます。
excludeしているのは、gradleでいうところの `compileOnly` がないため、dependencyでcompileで追加しつつ、jarに固める際に外しています。

https://github.com/h-r-k-matsumoto/spring-boot-sample/blob/micronaut-maven/pom.xml#L110-L130

```xml:pom.xml
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <artifactSet>
                                <excludes>
                                    <exclude>com.oracle.substratevm:*</exclude>
                                    <exclude>org.graalvm.truffle:*</exclude>
                                    <exclude>org.graalvm.sdk:*</exclude>
                                    <exclude>org.graalvm.compiler:*</exclude>
                                </excludes>
                            </artifactSet>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
```

### AnnotationProcessorの追加

compile時にannotationを独自に解析する拡張を有効化します。

https://github.com/h-r-k-matsumoto/spring-boot-sample/blob/micronaut-maven/pom.xml#L132-L160

```xml:pom.xml
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>io.micronaut</groupId>
                            <artifactId>micronaut-inject-java</artifactId>
                            <version>${micronaut.version}</version>
                        </path>
                        <path>
                            <groupId>io.micronaut.spring</groupId>
                            <artifactId>micronaut-spring-boot-annotation</artifactId>
                            <version>${micronaut.spring.version}</version>
                        </path>
                        <path>
                            <groupId>io.micronaut.spring</groupId>
                            <artifactId>micronaut-spring-web-annotation</artifactId>
                            <version>${micronaut.spring.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
```

### アプリケーションの起動
アプリケーションの起動方法を、　 `org.springframework.boot.SpringApplication#run` ではなく、下記のように、 `Micronaut#run`　に変更する必要があります。

```java:SpringBootSampleApplication.java
Micronaut.run(SpringBootSampleApplication.class, args);
```

### substratevm(AOT)における各設定

ここは・・・どうnative compileするかの定義ですが、細かくみていません。
nettyやlogging関連の設定ですが、とりあえずサンプルからのコピペです。

https://github.com/h-r-k-matsumoto/spring-boot-sample/blob/micronaut-maven/src/main/java/com/example/hrkm/springbootsample/graal/MicronautSubstitutions.java

## Build & Run

下記コマンドでdocker imageをビルドします。

```shell:build
$ docker build . -t spring-boot-sample:native-maven
```

実行します。

```shell:run
$ docker run -it --rm -p 8080:8080 spring-boot-sample:native-maven
15:28:54.834 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 23ms. Server Running: http://34f44eb544a3:8080
```

動いているか確認します。

```
$ curl localhost:8080/sample/hello
hello.%                                                                                        $
```

## 結果

### 得られたもの

- native-imageによる高速 (~30ms) な起動。

### 失ったもの

- `actuator` が動かない。`Micronaut.run`　に変えて　application.yamlから設定を読み込んでくれていない。<br>よってhealth checkができずにkubernetesで動かせなかった。いや、path変えればいいんだけども。。。
- `spring.profiles.active`　など実行時のプロファイル切り替えができない。

### 補足事項
下記にサポートされるアノテーション、されないアノテーション書いてます。例えば　`@JsonComponent` とかは対応されていないみたいです。

https://micronaut-projects.github.io/micronaut-spring/latest/guide/index.html

今後に期待ですね！
ソースレベルでMicronautにコンバートしてくれた方が嬉しいなぁ。

# 参考

- https://github.com/micronaut-projects/micronaut-spring
- https://github.com/micronaut-projects/micronaut-spring/tree/graal-native-image/examples/greeting-service