◀Table of Contents
Build a Spring Boot Application into a Native Executable
To package a Spring Boot application into a native executable, you need to use Spring Native, and add Maven/Gradle plugin for GraalVM Native Image (Native Build Tools) to automate the process.
-
Spring Native project provides support for compiling Spring applications ahead-of-time using GraalVM Native Image and eventually packaging them into lightweight containers. The target is to support any Spring applications, almost unmodified.
-
Native Build Tools provide Maven and Gradle plugins to add support for building Java applications into native executables and testing them using Apache Maven™. These plugins are maintained by the GraalVM team.
In this guide you will learn how to use Spring Native and the Maven plugin for GraalVM Native Image to add basic support and build a native executable for a Spring Boot application.
Note on a Sample Application
For the demo part, we will use a minimal REST-based API application, built on top of Spring Boot:
com.example.demo.DemoApplication
: the main Spring Boot class that defines the HTTP endpoint.com.example.demo.Jabberwocky
: a utility class that implements the logic of the application.
If we call the HTTP endpoint, /jibber
, it will return some nonsense verse generated in the style of the Jabberwocky poem, by Lewis Carroll.
The program achieves this by using a Markov Chain to model the original poem (this is essentially a statistical model).
This model generates a new text.
The example application provides the text of the poem, then generates a model of the text, which the application then uses to generate a new text that is similar to the original text.
The application uses the RiTa
library as an external dependency to build and use Markov Chains.
The pom.xml
file was generated using Spring Initializr with Spring Native Tools added as a feature.
Now we will go step-by-step explaining what necessary dependencies should be added to successfully convert a Spring Boot application into a native executable.
-
Clone the demo:
git clone https://github.com/graalvm/graalvm-demos.git
Find spring-native-image and open the demo folder in your favourite code editor or IDE. Open the Maven configuration file,
pom.xml
, to review what necessary dependencies were added. -
Find the Spring AOT plugin added to the default build configuration in plugins section. It performs ahead-of-time transformations of a Spring application into a native executable.
<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 is the first dependency that you have add to your Spring Boot projects if you plan to target GraalVM Native Image.
- Notice the Spring Native dependency in
<dependencies>
section, which provides native configuration APIs and other mandatory classes required to run a Spring application as a native executable. You need to specify it explicitly only with Maven.<dependency> <groupId>org.springframework.experimental</groupId> <artifactId>spring-native</artifactId> <version>${spring-native.version}</version> </dependency>
This is another required dependency.
-
See the required repositories added for Maven:
-
The repository for the
spring-native
dependency:<repositories> <repository> <id>spring-release</id> <name>Spring release</name> <url>https://repo.spring.io/release</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
-
The plugin’s repository for the Spring AOT plugin:
<pluginRepositories> <pluginRepository> <id>spring-release</id> <name>Spring release</name> <url>https://repo.spring.io/release</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories>
-
-
So far you learned how to configure build of Spring applications specifically. The next step is adding the Maven plugin for GraalVM Native Image that is a common requirement for any Java application. Find the
org.graalvm.buildtools:native-maven-plugin
plugin configuration inpom.xml
:<plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <version>${native-buildtools.version}</version> <executions> <execution> <id>build-native</id> <phase>package</phase> <goals> <goal>build</goal> </goals> </execution> </executions> <configuration> <imageName>${binary-name}</imageName> <skip>${skip-native-build}</skip> <buildArgs> <buildArg>-H:+ReportExceptionStackTraces ${native-image-extra-flags}</buildArg> </buildArgs> </configuration> </plugin>
Notice how we pass the configuration arguments to the underlying
native-image
tool using the<buildArgs>
section. In individualbuildArg
tags, you can pass all Native Image parameters as you would pass them to thenative-image
tool on the command line. -
To avoid classes clash between Spring Boot packaging and the
native-maven-plugin
build, we customized a Spring Boot classifier:- Included
<repackage.classifier/>
into project’s general properties:<properties> <java.version>17</java.version> <repackage.classifier/> <spring-native.version>0.11.4</spring-native.version> </properties>
- Modified
native
profile so to includerepackage.classifier
:<profiles> <profile> <id>native</id> <properties> <repackage.classifier>exec</repackage.classifier> </properties> ... </profile> </profiles>
- Modified the
spring-boot-maven-plugin
configuration to include the classifier:<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>
This Spring Boot application is now ready to be built and compiled ahead-of-time into a native executable.
- Included
-
From a console window, enter the application root directory and build the application:
cd graalvm-demos/spring-native-image && mvn clean package
This will generate a runnable JAR file that contains all of the application’s dependencies and also a correctly configured
MANIFEST
file.As a nice extra, there is also a Dockerfile provided with this demo. So, besides building the application JAR, you see a Docker image being built at
mvn clean package
step, pulling the GraalVM container image,ghcr.io/graalvm/jdk:ol8-java17
, as the JVM.You can also test running this application from a JAR:
java -jar ./target/benchmark-jibber-0.0.1-SNAPSHOT.jar &
where
&
brings the application to the background. Call the endpoint:curl http://localhost:8080/jibber
Bring the app back to the foreground and terminate:
fg ctrl+C
-
Next build a native executable for this Spring Boot application using the Maven profile:
mvn package -Dnative
It will generate a native executable for the platform in the target directory, called
jibber
. -
Run the application from a native executable. Execute the following command in your terminal and put it into the background, using
&
:./target/jibber &
Call the endpoint to test it using the
curl
command:curl http://localhost:8080/jibber
Notice how fast this native version of your Spring Boot application starts. It also uses fewer resources than running from JAR.
You should get some nonsense verse back. To terminate it, first bring the application to the foreground,
fg
and kill<ctrl-c>
.Last, check the executable file size to compare the footprint:
ls -lh target/jibber
You can further “shrink” this native executable by containerising and running it from a Docker container.
Related Documentation
- Run an interactive lab: GraalVM Native Image, Spring and Containerisation. This lab will also show how to create small Distroless containers to package your GraalVM Native Image native executables in, allowing you to shrink your Docker Images even further.
- Package a Spring application to lightweight Docker container containing a native executable with Spring Boot Buildpacks.
- Learn more about the Spring Native project.
- Read more about Native Build Tools.