Spring Boot 3 meets Graal Native Image
Tags: springboot, graal, native
Published: 2022-10-29 10:14:43


Spring Boot 3 is the upcoming big release for spring boot. Based on Spring Framework 6, this release is packed with many new features. One thing that has generated a lot of interest in dev community is Graal native image support. Spring Boot 3 comes with out of the box support for generating native images, which promises fast startup time. Spring already has an experimental project `Spring Native` to support graal native image generation, however from 3.x version it comes out of box with Spring Boot and no new module is needed. 

> `Spring Native` is going to be discontinued. 


## How to generate native image

Let's first generate a spring boot project from `start.spring.io` . Add `GraalVM Native Support` to the list of dependencies. 

> Currently it requires Graal VM 22.3 version. 

There are three ways to generate native image - 

* **Using buildpack** - spring-boot-maven-plugin can make use of buildpacks to generate an image with native executable. The generated pom has the below plugin

```xml
<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<image>
						<buildpacks>
							<buildpack>gcr.io/paketo-buildpacks/bellsoft-liberica:9.9.0-ea</buildpack>
							<buildpack>gcr.io/paketo-buildpacks/java-native-image</buildpack>
						</buildpacks>
					</image>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
```

it uses liberica buildpack which uses Graal 22.3 support.

with this if you run `spring-boot:build-image` an OCI compatible image will be generated which uses native executable . 

> To see how buildpacks work check out my post https://dev.to/sabyasachi/buildpack-with-spring-boot-300o

* **Using Maven** - `spring-boot-starter-parent` comes with graal `native-image-plugin` in profile `native`. The below command generates an executable for your local machine architecture - 

```
mvn -Pnative native:compile
```
We need to have graal 22.3 installed on local machine, 

> As of writing this post I could only found `22.3.r17.ea-nik` distribution via sdk man. In case you do not see this distribution in sdk list try setting `sdkman_beta_channel=true` in `~/.sdkman/etc/config` file. 



* **Using aot processed jar** - Most of us might be transitioning from using uber jar to native image. We might want to support both before we gain enough confidence and operational excellence. If we run `mvn package` an aot processed jar will be generated, which then can be used with `native-image` tool to generate native executable artifact. I see this option as a great entrypoint to adopt graal native image. 

## Graal reachability metadata support

During native image generation, native-image tool does a static analysis. There are classes which might not get accessed during this static analysis and they get left out in the final artifact. To overcome this some extra information can be provided during build time. Creating this extra metadata is cumbersome. There's an effort to consolidate these metadata information for various 3rd party libraries into a shared github repo https://github.com/oracle/graalvm-reachability-metadata .

During generation of native image spring makes use of this repo to include already known configs and hence makes the build much easier. 


## Testing with Native image

The official document guides us to write unit and integration test and test it with the JVM version of the application. This will lower the feedback time as compiling native image still takes a lot of time (approx 7-8 min in my 2019 Macbook Pro) . 

However, there's a nice feature to run the aot compiled jar and run some integration test against it . 

## What I like and didn't like

Likes 

- Building of graal native image has improved a lot and having it out of the box will really help its adoption. 
- GraalVM reachability metadata is a great addition to help compatibility issues. 
- Faster startup . 
- AOT processed artifact. 
- I was able to use flyway with postgres seamlessly , previously when I tried with Spring native image this integration didn't work . 

Things that need to keep in mind-

- As I add spring boot actuator and had jmx enabled, startup of my application failed. I need to disable expose of management endpoint via JMX as JMX is not supported in Graal native image. 
- Configartion like `@Profile` and `@ConditionalOnProperty` is not supported. These are used very frequently .
- Build time is still on a little longer side. On my personal 2019 MacBook Pro it tool approx 7-8min . 
- We need to expect compatibility issue with 3rd Party libs. 
- no JVMTI or Java Agents support. 
- No thread dump,heap dump . 

Both Graal native image and Spring's support is still is very early days. Right now I see graal native can be fit very aptly in Serverless world where we need fast startup. Absence of JIT compilation, JVMTI, JMX those does not come into play in a lean serverless world. 

If I compare Spring with  Micronaut or Quarkus support for graal native I must say Spring is catching up very fast. Support for reachability metadata is a nice addition in spring. 

Overall, yes it is promising but my only concern remains with compatibilty with other libs , longer build time and features that are not supported in native image .