Building Spring Boot Native Applications
Spring team is developing spring native module which provides support for compiling Spring applications to native executables using the GraalVM native-image compiler.
Native applications provide following advantages compared to JVM based applications
- Faster starup time
- Instant peak performance
- Reduced memory usage
Required software
- Spring Boot 2.5.6
- Graal VM 11 (Community Edition)
- Maven 3.8+
- Docker
Setting up the project
To create a project, go to https://start.spring.io and select following spring version and dependencies.
- SpringBoot version 2.5.6
- spring-boot-starter-web
- spring-boot-starter-data-jpa
- h2
- spring-native
Note |
1) Spring Native 0.10.5 only supports Spring Boot 2.5.6 2) Native images can be created with Java 8 and 11 versions only 3) Java17 version is not supported for native image creation as of writing this blog post. 4) Examples in this blog post are tested with only Java 11 version on Windows machine. |
Warning |
native-image generation needs a lot of RAM, you should have a machine with at least 16GB of RAM to try out the example. |
Download the project, extract and import it into your favourite IDE.
Building Native Image
There are 2 main ways to build a Spring Boot native application
- Using Spring Boot Buildpacks support to generate a lightweight container containing a native executable.
- Using the GraalVM native image Maven plugin support to generate a native executable.
i) With Build Packs
Adding Spring Native module dependency adds all the required plugins and configurations to pom.xml file by spring starter project.
You can observe following module in dependency
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</dependency>
Code language: Java (java)
In plugins section
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>${repackage.classifier}</classifier>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
<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>
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>${hibernate.version}</version>
<executions>
<execution>
<id>enhance</id>
<goals>
<goal>enhance</goal>
</goals>
<configuration>
<failOnError>true</failOnError>
<enableLazyInitialization>true</enableLazyInitialization>
<enableDirtyTracking>true</enableDirtyTracking>
<enableAssociationManagement>true</enableAssociationManagement>
<enableExtendedEnhancement>false</enableExtendedEnhancement>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Code language: Java (java)
Spring AOT PlugIn : The Spring AOT plugin performs ahead-of-time transformations required to improve native image compatibility and footprint.
Hibernate Enhance Plugin : The goal of the Hibernate Enhance plugin is to instrument the JPA entity bytecode in order to improve the effectiveness and efficiency of the associated data access operations.
The Native application can be built with the following command.
mvn spring-boot:build-image
Code language: Bash (bash)
The above command creates a Linux container to build the native application using the GraalVM native image compiler. By default, the container image is installed locally.
Run the native application
docker run --rm -p 8080:8080 springboot-native-image:0.0.1-SNAPSHOT
Code language: Bash (bash)
Now , you should be able to test the application with Rest client.
Note |
Native Image creation is very time taking process. It might take up to 10 min. to create the image depending on your system processing power. |
Tip |
On Windows, make sure to enable the Use the WSL 2 based engine (if WSL2 is installed on your computer) for better performance in Docker during image creation |
The Paketo Java Native Image Buildpack internally uses GraalVM to build native image.
By default, GraalVM versions will be upgraded automatically by Buildpacks to the latest release.
If we want to explicitly configure Spring Boot Maven or Gradle plugins with a specific version of java-native-image
buildpack which will freeze GraalVM version, For example, if you want to force using GraalVM 21.2.0
, you can configure like below in spring boot maven plugin
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- ... -->
<image>
<buildpacks>
<buildpack>gcr.io/paketo-buildpacks/java-native-image:5.5.0</buildpack>
</buildpacks>
</image>
</configuration>
</plugin>
Code language: Java (java)
You can visit the link to know the version mapping between GraalVm and Java Native Image Buildpack Version.
ii) With GraalVM native build tools
We need to install the Gra
A number of prerequisites are required before installing the GraalVM native-image
compiler.
i) Download and Install GraalVM CE 21.2.0 (Java 11) version from here based on your operating system
ii) Set the Graal VM as the default JVM on your system.
On Linux
Instructions for changing default Java provider depends on Linux distribution.
For Ubuntu instructions, visit this link
For Manjaro/Arch instructions, visit this link
On Windows
Set JAVA_HOME
to GraalVM installation directory
and PATH
to GraalVM installation bin directory
iii) Run the below command to bring native-image extensions to the JDK
On Linux
${GRAALVM_HOME}/bin/gu install native-image
Code language: Bash (bash)
On Windows
%JAVA_HOME%\bin\gu install native-image
Code language: Bash (bash)
Make sure that, you are using GraalVm as default JVM with Maven by running below command
mvn --version
Code language: Bash (bash)
In pom.xml add the following plugin configuration under native profile.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
Code language: XL (xl)
Now run the below command to build native application
On Linux
mvn -Pnative -DskipTests package
Code language: Bash (bash)
On Windows
Download and Install Visual Studio 2019 Visual C++ Build Tools and Visual Studio 2019 community edition.
Now search for x86_x64 cross tools command prompt for VS 2019
and open the command prompt by clicking on it.
Now navigate to project folder and run following command
mvn -Pnative -DskipTests package
Code language: Bash (bash)
The above command will create exe file in the target folder
Run the native application
./target/springboot-native-image.exe
Code language: Bash (bash)
Let’s test native application with a Rest client
Comparing the startup times
Let’s compare the JVM (jar) and native application start-up times.
JVM (Jar) version start-up time is 4.907 seconds and Native application start-up time is 0.727 seconds
Troubleshooting
I faced the following issues while building the native applications.
Image build request failed with exit status 137
You might see error message like below when the system does not have enough memory to build the native image.
Try to use the system with at least 1GB of RAM.
Error: Image build request failed with exit status 137
Builder lifecycle ‘creator’ failed with status code 145
This is a generic error triggered by Docker and forwarded by Spring Boot Buildpacks support. native-image
command has likely failed, so check the error messages in the output. If you can’t find anything, check if that’s not an out of memory error as described above.
You can download the source code for blog post from GitHub
You might be also interested in