Spring Native: What, Why and How?

Spring Native makes sure we can compile Spring applications to a native executable. To get these native executables Spring Native uses the GraalVM Native Image compiler.

In this article we will go over what is GraalVM Native images, what is Spring Native. We also will go over some advantages and disadvantages of using Spring Native. We will also try to answer the question: ‘When do we use Spring native?’. Last but not least we will create a small application and build a native image from it with the tools that Spring provides us.

Spring Native is in Beta

What are GraalVM Native Images?

What is Spring Native?

Advantages for native images

Faster startup

  • No class loading: All classes will already we loaded and even partially initiated during build time. This is made possible with the AOT compiler.
  • No interpreted code: We don’t have to initialize an interpreter and interpret byte-code
  • No JIT: We don’t have to spend any CPU resources to start a JIT compiler or use a JIT compiler
  • Generating Image Heap during build: Because we can already partially initiate classes at build time, we can also run some initialization processes at build time. So when we startup we don’t have to execute that part anymore

Lower memory usage

The native image will have less memory usage which makes is more suitable for Docker Images, just to give an example. How does a native image achive this?

  • No metadata for loaded classes
  • No profiling data for JIT
  • No Interpreter code

Building an example Native Image Disadvantages for native images

No Java agents, JMX, JVMTI, Java Flight Recorder support

Some of these features are really handy to manage, test and control your JVM applications. Because the native images does not live in a JVM container these features are not available.

Reflection requires extra config

Reflection is widely used in a lot of frameworks so those frameworks need to do extra configuration and work to support native images. That is why Spring created the Spring Native project.

No dumps

You will not be able to able to use thread and heap dumps. There are ways to fetch some information about threads by using Linux Kernel features.

When do we best use Spring Native?

You best you Spring Native images when you are building CLI tools or create some serverless functions. This all has to do with the short live span of the application and the faster startup time. Spring Cloud Functions fit really good with native images.

Building an example Native Image

Generating the project

First step Spring Initializr IntelliJ
Second step Spring Initializr IntelliJ

The important dependency we selected is Spring Native [Experimental]. If you open your pom.xml you can see that is added a Spring Native dependency:

<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</dependency>

Another thing I should mention that there is a spring-aot-maven-plugin added to the pom.xml:

<plugin>
<
groupId>org.springframework.experimental</groupId>
<
artifactId>spring-aot-maven-plugin</artifactId>
<
version>${spring-native.version}</version>
<
executions>
<
execution>
<
id>test-generate</id>
<
goals>
<
goal>test-generate</goal>
</
goals>
</
execution>
<
execution>
<
id>generate</id>
<
goals>
<
goal>generate</goal>
</
goals>
</
execution>
</
executions>
</
plugin>

This plugin is used to compile your Spring application code to make it ready for native execution. This plugin will also add all the configuration that is needed to handle the Reflection that Spring uses.

Run AOT generate after every build

Go to the Maven tool window open up plugins then open up spring-aot. After that right click on spring-aot:generate and select Execute after build.

The result of the previous action

Adding a simple endpoint

@Bean
public RouterFunction<ServerResponse> routes() {
return route()
.GET("/", request -> ServerResponse.ok().body(Mono.just("Hello everyone!\n"), String.class))
.build();
}

If we now run our application and use curl to get the endpoint we should see the following:

The result

Please stop the application again so we can build our Native Image.

Building the image

$ mvn clean package
$ mvn spring-boot:build-image

The result of the last command will be the following docker image: spring-native-example:0.0.1-SNAPSHOT

$ docker images

The docker images command gives the following:

Docker Images

Now it’s time to start the docker image and trigger our endpoint again to see if we have the same result:

$ docker run --name spring-native-example -p 8080:8080 spring-native-example:0.0.1-SNAPSHOT

The following result:

Output of a native image

One thing to note here is that we already see an advantage and that is the fast startup time. The native image for me started in 0.035 seconds, while when I start it from IntelliJ Spring tells me it takes 0.995 seconds.

And if we curl to the application again we see the same result so our endpoint is working as expected:

The result

Conclusion

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store