Micronautフレームワークを使ってみよう

What is Micronaut?

Micronaut(まいくろのーと)とは、JVMベースのフルスタックフレームワークです。
2018年5月にOSSとして公開され、先日最新バージョンの1.1がリリースされました。
Java/Groovy/Kotlinで実装することができ、テストしやすくコンテナ化も容易、
クラウドネイティブなアプリも簡単に構築できるようです。

Features of Micronaut

Micronautの主な特徴について、ここで説明している内容から抜粋して紹介します。

Fast start up & low memory consumption

リフレクションベースのIoCフレームワークだと、
すべてのフィールドやメソッドのリフレクションデータをロードしてキャッシュしますが、
Micronautではアプリケーションのコードベースのサイズに左右されないので、
起動が速く、メモリ消費も少なくすることができます。

Micronaut usging Graal VM

Micronautは、リフレクションを使用しないDIとAOPランタイムを持っているので、
アプリをGraalVM上で実行することが容易です。
GraalVMを使用すれば、わずか数十ミリ秒でMicronautアプリが起動します。
* GraalVM : Oracleの汎用VM.Javaアプリをネイティブのマシンコードにコンパイルする機能を持つ

fast & easy Testing

Unitテストでサーバを簡単に起動し、すぐに実行可能です。

import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.*

class HelloClientSpec extends Specification {
    @Shared
    @AutoCleanup
    EmbeddedServer embeddedServer =
        ApplicationContext.run(EmbeddedServer)

    @Shared
    HelloClient client = embeddedServer
        .applicationContext
        .getBean(HelloClient)

    void "test hello world response"() {
        expect:
        client.hello().blockingGet() == "Hello World"
    }
}

compile time DI & AOP

Micronautではリフレクションを使わずにコンパイル時のAOPを提供しています。
だからGraalVMとかでも簡単に動かせるんですね。

@Scheduled(fixedRate = "5m")
@Retry(attempts='5')
void everyFiveMinutes() {
    messageService.sendMessage("Hello World");
}

Build Reactive application

Micronautは、Reactive Streamを実装するフレームワーク(RxJavaとか)をサポートします。

@Client( id = "person-service" )
public interface PersonClient {
    public io.reactivex.Single<Person>
        save(@Body Single<Person>person)
}

Micronaut Profiles

Micronautにはデフォルトで複数のプロファイルが組み込まれています。
プロファイルを使うことでアプリの雛形を生成したり、
対象プロファイル用のコマンドを使用することができます。

これは、後述するcreate-appコマンド(Micronautアプリを生成するコマンド)を使った場合、
コントローラ(create-controller)、クライアント(create-client)を
生成するためのコマンドが使えるようになったりします。

Clound Native

MicronautではGoogle Cloud Platform(GCP)やAmazon Web Services(AWS)を
統合したモジュールを提供しています。
これらを用いることにより、各種クラウドプラットフォームに対応したMicronautアプリを作成できます。

参考: Micronaut GCP Micronaut AWS

また、Micronaut AWSを使うと、AWS Lambdaを使ったMicronautアプリを作成することができます。
(Alexa SkillsとかAWS API Gatewayもサポート)

message driven

RabbitMQを統合したMicronaut RabbitMQモジュールを使えば、
Micronautアプリでメッセージ駆動型サービスが作成可能になります。
また、RabbitMQプロファイルを使用すれば、
producerとlistenerを作成する固有コマンドを使うことができます。

% mn create-app sample-mq-service --profile rabbitmq

% mn create-rabbitmq-producer Message # make producer
% mn create-rabbitmq-listener Message # make listener

develop serverless application

さきほどMicronaut AWSモジュールでLambdaアプリが開発できるといいました。
Micronautの、コンパイルタイムDI&AOPであればサーバーレス用関数を書くのに適しています。

@Field
@Inject
HelloService helloService

Message hello(Person person) {
    helloService.hello(person)
}

resilient microService

分散環境における障害対策であるとサーキットブレーカーなどの機能がデフォルトで組み込まれています、

import io.micronaut.retry.annotation.*

@CircuitBreaker(reset = "30s")
public List findBooks() {
    ...
    ..
}

環境

今回使用した動作環境は以下のとおりです。

  • OS : MacOS X 10.12.6
  • Java : 1.8.0_212

Setup Micronaut

ではMicronautをインストールしてみましょう。
sdkmanを使うと簡単にセットアップできるので、まずはsdkmanをインストールします。

% curl -s "https://get.sdkman.io" | bash
% sdk version

SDKMAN 5.7.3+337

次に、micronautをインストールします。

% sdk install micronaut
==== BROADCAST =================================================================
* 2019-07-13: Groovy 3.0.0-beta-2 released on SDKMAN! #groovylang
* 2019-07-11: Grails 4.0.0 released on SDKMAN! #grailsfw
* 2019-07-10: Gradle 5.5.1 released on SDKMAN! #gradle
================================================================================

Downloading: micronaut 1.1.4

In progress...

######################################################################## 100.0%

Installing: micronaut 1.1.4
Done installing!


Setting micronaut 1.1.4 as default.

mnコマンドが使えるようになっていればMicronautのインストールは完了です。

% mn --version                             
Resolving dependencies..
| Micronaut Version: 1.1.4
| JVM Version: 1.8.0_212

Hello Micronaut

Micronautアプリを作成してみましょう。
mn create-appコマンドを使えばシンプルなプロジェクトを生成できます。

% mn create-app example.micronaut.complete
| Generating Java project...
| Application created at /path/your/micronaut/complete

生成したプロジェクトはgradleをつかったプロジェクトとなっています。
IDEA等のIDEを使えば、そのまま開いて編集することが可能です。

最初にシンプルなControllerを作成します。
このControllerは/hello宛のGETリクエストを受けると文字列を返します。

// path/your/prject/complete/src/main/java/example/micronaut/HelloController.java
package example.micronaut;

import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Produces;

@Controller("/hello")
public class HelloController {
    @Get("/")
    @Produces(MediaType.TEXT_PLAIN)
    public String index() {
        return "Hello World";
    }
}

Controllerに対するテストも作成してみましょう。
@MicronautTestを使えばテストも簡単に作成可能です。

// path/your/prject/complete/src/test/java/example/micronaut/HelloControllerTest.java
package example.micronaut;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import io.micronaut.http.HttpRequest;
import io.micronaut.http.client.RxHttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;

@MicronautTest
public class HelloControllerTest {

    @Inject
    @Client("/")
    RxHttpClient client;

    @Test
    public void testHello() {
        HttpRequest<String> request = HttpRequest.GET("/hello");
        String body = client.toBlocking().retrieve(request);

        assertNotNull(body);
        assertEquals("Hello World", body);
    }
}

gradleでtestを実行してみます。

% ./gradlew test
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

> Task :test

BUILD SUCCESSFUL in 39s
4 actionable tasks: 2 executed, 2 up-to-date

runコマンドで起動してみましょう。

% ./gradlew run 

> Task :run
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
17:12:14.213 [main] INFO  io.micronaut.runtime.Micronaut 
- Startup completed in 6380ms. Server Running: http://localhost:8080
> :run

Controllerにcurlでアクセスしてみます。

%curl http://localhost:8080/hello
Hello World

まとめ

今回はJVMベースのフルスタックフレームワーク、Micronautを少しだけ使ってみました。
機能説明でいったとおり、MicronautではCloud用モジュールが用意されていたり
GraalVMで動かしたりも可能なので、いろいろと試して見ようかと思います。

参考サイト

infoq : https://www.infoq.com/jp/news/2019/07/micronaut-1.1-cloud-native
Micronaut公式 : https://micronaut.io/