Springは、JavaまたはKotlinで記述された既存のSpring BootアプリケーションをGraalVMネイティブイメージに変換するための新しいツール Spring Native Beta をリリースした。目標は、Spring NativeでSpring Bootアプリケーションをサポートすることだ。GraalVMネイティブイメージは小さく、最適化され、すばやく起動する。ただし、トレードオフとして、JVMと比較して、ビルド時間が長くなり、実行時の最適化が少なくなる。
過去18か月間GraalVMチームと、Spring Nativeが従来のSpring BootコードをGraalVMが確実に理解するブリッジとして機能するよう協力してきた。Oracle LabsのシニアリサーチマネージャであるVojin Jovanovic氏は、Springとのコラボレーションについて次のように述べている:
ネイティブJVMエコシステムの作成でSpringチームと協力することは大きな喜びです: コミュニティへの繊細なタッチに包まれた彼らの深い技術的知識は、常に最良のソリューションにつながります。最新のSpring NativeリリースとJVMエコシステムでの多くの使用法は、ネイティブコンパイルの幅広い採用への道を開きます。
内部的には、MavenとGradleによって提供される事前 (AOT) プラグインを使用して、Spring Bootアプリケーションをネイティブコードに変換する。これらのプラグインは、GraalVMでサポートされていないリフレクションやプロキシなど、すべてのSpring要素のGraalVMネイティブ構成を生成する。構成の結果は、 reflect-config.json
ファイルに保存される。たとえば、@Service
アノテーションが付けられた各クラスはJSONファイルに構成される。
Spring Native構成ファイルは、META-INF/native-image
フォルダにあると仮定して検出される。Nativeヒントは、MySQLドライバ構成など、Spring Nativeが (まだ) サポートしていない要素を構成するために使用できる。
Spring Nativeの依存関係は、新しいプロジェクトを作成するときに Spring Initializr が使用できる。
Spring Data JPAなどの一部の依存関係では、GraalVMをサポートするために追加の構成が必要だ。Springチームは、プラグインを介してこれらの追加構成を提供する。たとえば、Spring Data JPA依存関係がIntitializrに追加された後、2つの追加のMavenプラグイン、spring-aot-maven-plugin
とhibernate-enhance-maven-plugin
が、構成を含めて pom.xml
ファイルに追加される。
現時点では、すべての依存関係がSpring Nativeでサポートされているわけではない。Intializrによって生成されたSpringプロジェクトにサポートされていない依存関係が含まれている場合、HELP.md
ファイルにその依存関係がリストされる。
他のSpring Bootアプリケーションと同様に、Initializrは、アプリケーションを実行するための適切なエントリポイントクラスを自動的に作成する:
@SpringBootApplication
public class NativeApplication {
public static void main(String[] args) {
SpringApplication.run(NativeApplication.class, args);
}
}
次に、アプリケーションをテストするためのRESTコントローラを提供する:
@Controller
public class NativeEndpoint {
@GetMapping("/native")
public String nativeCall() {
return "Native";
}
}
標準のSpring Boot依存関係の他に、SpringネイティブサポートのためにInitializrによって1つの新しい依存関係が追加されている:
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</dependency>
spring-boot-maven-plugin
は、ネイティブイメージを生成するための追加の構成を受け取っている:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
Mavenは、事前コンパイルでネイティブイメージを生成できる。結果の実行可能ファイルには、必要なすべてのクラスと、JDKから静的にリンクされたネイティブコードが含まれる。ランタイムシステムとして、「通常の」Java VMの代わりにSubstrate VMが使用される。
$ ./mvnw spring-boot:build-image
コードのコンパイルと最適化のためイメージのビルドには時間がかかる。このステップはDockerイメージで実行され、かなりのメモリを必要とする。次のエラーが発生した場合は、Dockerのメモリ設定を増やす必要がある:
Exception in thread "native-image pid watcher" java.lang.OutOfMemoryError:
GC overhead limit exceeded
上記のMavenコマンドの実行からの出力は、GraalVMネイティブイメージを含む結果のDockerイメージを表示する:
Successfully built image 'docker.io/library/native:0.0.1-SNAPSHOT'
結果のイメージは約82MBで、アプリケーションを実行するためのすべてが含まれている:
$ docker images
native 0.0.1-SNAPSHOT ... 81.9MB
Dockerコンテナが 8080 ポートで開始される:
$ docker run -p 8080:8080 native:0.0.1-SNAPSHOT
コンテナが開始された後、アプリケーションはほとんど瞬時にテスト可能になる:
$ curl localhost:8080/native --silent
Native
Dockerを使用してGraalVMをインストールする代わりの方法など、詳細についてはSpring Nativeのドキュメントを参照してください。
Springチームは、Spring Nativeを他のSpringプロジェクトと組み合わせて使用する方法について多数のサンプルコードを提供している。GraalVMのパフォーマンスとSpring BootとGraalVMネイティブイメージの統合に関するより詳細な情報を含むQConとSpringOneのプレゼンテーションも利用できる。