git clone https://github.com/openliberty/guide-spring-boot.git
cd guide-spring-boot
Contents
- What you’ll learn
 - Getting started
 - Building and running the application
 - Building and running the application in a Docker container
 - Optional: Faster container startup with InstantOn
 - Running the application on Open Liberty
 - Packaging the application embedded with Open Liberty
 - Great work! You’re done!
 - Guide Attribution
 
Tags
Containerizing, packaging, and running a Spring Boot application
Prerequisites:
Learn how to containerize, package, and run a Spring Boot application on Open Liberty without modification.
What you’ll learn
The starting point of this guide is the finished application from the Building an Application with Spring Boot guide. If you are not familiar with Spring Boot, complete that guide first. Java 21 is required to run this project.
You will learn how to use the springBootUtility command to deploy a Spring Boot application in Docker on Open Liberty without modification. This command stores the dependent library JAR files of the application to the target library cache, and packages the remaining application artifacts into a thin application JAR file. Optionally, you will learn how to use Liberty InstantOn with your Spring Boot application for faster startup.
You will also learn how to run the Spring Boot application locally with Open Liberty, and how to package it so that it is embedded with an Open Liberty server package.
Getting started
The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:
The start directory contains the starting project that you will build upon.
The finish directory contains the finished project that you will build.
Before you begin, make sure you have all the necessary prerequisites.
Building and running the application
First, build the initial Spring Boot application into an executable JAR file. Navigate to the start directory and run the Maven package command:
WINDOWS
MAC
LINUX
cd start
mvnw.cmd package
cd start
./mvnw package
cd start
./mvnw package
You can now run the application in the embedded Tomcat web container by executing the JAR file that you built:
java -jar target/guide-spring-boot-0.1.0.jar
After you see the following messages, the application is ready:
... INFO ... [ main] com.example.springboot.Application : Started Application in 2.511 seconds (process running for 3.24) Let's inspect the beans provided by Spring Boot: application ... welcomePageHandlerMapping welcomePageNotAcceptableHandlerMapping
Go to the http://localhost:8080/hello URL to access the application.
The following output is displayed in your browser:
Greetings from Spring Boot!
When you need to stop the application, press CTRL+C in the command-line session where you ran the application.
Building and running the application in a Docker container
You will build an Open Liberty Docker image to run the Spring Boot application. Using Docker, you can run your thinned application with a few simple commands. For more information on using Open Liberty with Docker, see the Containerizing microservices guide.
Learn more about Docker on the official Docker website.
Install Docker by following the instructions in the official Docker documentation.
Navigate to the start directory.
Create theDockerfilein thestartdirectory.Dockerfile
Dockerfile
 1# Stage and thin the application 
 2# tag::OLimage1[]
 3FROM icr.io/appcafe/open-liberty:full-java21-openj9-ubi-minimal AS staging
 4# end::OLimage1[]
 5
 6# tag::copyJar[]
 7COPY --chown=1001:0 target/guide-spring-boot-0.1.0.jar \
 8                    /staging/fat-guide-spring-boot-0.1.0.jar
 9# end::copyJar[]
10
11# tag::springBootUtility[]
12RUN springBootUtility thin \
13 --sourceAppPath=/staging/fat-guide-spring-boot-0.1.0.jar \
14 --targetThinAppPath=/staging/thin-guide-spring-boot-0.1.0.jar \
15 --targetLibCachePath=/staging/lib.index.cache
16# end::springBootUtility[]
17
18# Build the image
19# tag::OLimage2[]
20FROM icr.io/appcafe/open-liberty:kernel-slim-java21-openj9-ubi-minimal
21# end::OLimage2[]
22
23ARG VERSION=1.0
24ARG REVISION=SNAPSHOT
25
26LABEL \
27  org.opencontainers.image.authors="Your Name" \
28  org.opencontainers.image.vendor="Open Liberty" \
29  org.opencontainers.image.url="local" \
30  org.opencontainers.image.source="https://github.com/OpenLiberty/guide-spring-boot" \
31  org.opencontainers.image.version="$VERSION" \
32  org.opencontainers.image.revision="$REVISION" \
33  vendor="Open Liberty" \
34  name="hello app" \
35  version="$VERSION-$REVISION" \
36  summary="The hello application from the Spring Boot guide" \
37  description="This image contains the hello application running with the Open Liberty runtime."
38
39# tag::serverXml[]
40RUN cp /opt/ol/wlp/templates/servers/springBoot3/server.xml /config/server.xml
41# end::serverXml[]
42
43RUN features.sh
44
45# tag::libcache[]
46COPY --chown=1001:0 --from=staging /staging/lib.index.cache /lib.index.cache
47# end::libcache[]
48# tag::thinjar[]
49COPY --chown=1001:0 --from=staging /staging/thin-guide-spring-boot-0.1.0.jar \
50                    /config/dropins/spring/thin-guide-spring-boot-0.1.0.jar
51# end::thinjar[]
52
53RUN configure.sh 
This Dockerfile is written in two main stages. For more information about multi-stage Dockerfiles, see the documentation on the official Docker website.
The first stage copies the guide-spring-boot-0.1.0.jar Spring Boot application to the /staging temporary directory,
and then uses the Open Liberty springBootUtility command to thin the application. For more information about the springBootUtility command, see the springBootUtility documentation.
The second stage begins with the Open Liberty Docker image. The Dockerfile copies the Liberty server.xml configuration file from the /opt/ol/wlp/templates directory, which enables Spring Boot and TLS support. Then, the Dockerfile copies the Spring Boot dependent library JAR files that are at the lib.index.cache directory and the thin-guide-spring-boot-0.1.0.jar file. The lib.index.cache directory and the thin-guide-spring-boot-0.1.0.jar file were both generated in the first stage.
Use the following command to build the Docker image:
docker build -t springboot .
To verify that the images are built, run the docker images command to list all local Docker images:
docker images
Your springboot image appears in the list of Docker images:
REPOSITORY    TAG       IMAGE ID         CREATED           SIZE
springboot    latest    3a5492c0cbeb     27 seconds ago    485MB
Now, you can run the Spring Boot application in a Docker container:
docker run -d --name springBootContainer --rm -p 9080:9080 -p 9443:9443 springboot
Before you access your application from the browser, run the docker ps command to make sure that your container is running:
docker ps
You see an entry similar to the following example:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e33532aa07d6 springboot "/opt/ol/helpers/run…" 7 seconds ago Up 2 seconds 0.0.0.0:9080->9080/tcp, 0.0.0.0:9443->9443/tcp springBootContainer
You can watch the application start by monitoring the logs:
docker logs springBootContainer
Wait several seconds for the following message, which indicates that Liberty’s startup is complete:
... CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 8.033 seconds. ... CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 11.065 seconds.
Note that the thin-guide-spring-boot-0.1.0 application took 8.033 seconds to start.
After the application starts, go to the http://localhost:9080/hello URL to access the application.
After you are finished checking out the application, stop your container by running the following command:
docker stop springBootContainer
Optional: Faster container startup with InstantOn
Liberty InstantOn provides fast startup times for MicroProfile and Jakarta EE applications. In this section, you’ll learn how to build an InstantOn image that provides fast startup times. Your application can start in milliseconds, without compromising on throughput, memory, development-production parity, or Java language features.
Liberty InstantOn requires a Linux system with kernel version 5.9 or greater. You can run the following command to check the kernel version of your system:
uname -r
If your kernel version is older than 5.9, you can skip this section and move on to the Running the application on Open Liberty section.
The Coordinated Restore at Checkpoint (crac) Liberty feature enables applications to use the Liberty InstantOn implementation of the org.crac APIs. When the org.crac APIs are enabled, checkpoint and restore can work with applications written using the Spring Framework.
Replace theDockerfilein thestartdirectory.Dockerfile
Dockerfile
 1# Stage and thin the application 
 2# tag::OLimage1[]
 3FROM icr.io/appcafe/open-liberty:full-java21-openj9-ubi-minimal AS staging
 4# end::OLimage1[]
 5
 6# tag::copyJar[]
 7COPY --chown=1001:0 target/guide-spring-boot-0.1.0.jar \
 8                    /staging/fat-guide-spring-boot-0.1.0.jar
 9# end::copyJar[]
10
11# tag::springBootUtility[]
12RUN springBootUtility thin \
13 --sourceAppPath=/staging/fat-guide-spring-boot-0.1.0.jar \
14 --targetThinAppPath=/staging/thin-guide-spring-boot-0.1.0.jar \
15 --targetLibCachePath=/staging/lib.index.cache
16# end::springBootUtility[]
17
18# Build the image
19# tag::OLimage2[]
20FROM icr.io/appcafe/open-liberty:kernel-slim-java21-openj9-ubi-minimal
21# end::OLimage2[]
22
23ARG VERSION=1.0
24ARG REVISION=SNAPSHOT
25
26LABEL \
27  org.opencontainers.image.authors="Your Name" \
28  org.opencontainers.image.vendor="Open Liberty" \
29  org.opencontainers.image.url="local" \
30  org.opencontainers.image.source="https://github.com/OpenLiberty/guide-spring-boot" \
31  org.opencontainers.image.version="$VERSION" \
32  org.opencontainers.image.revision="$REVISION" \
33  vendor="Open Liberty" \
34  name="hello app" \
35  version="$VERSION-$REVISION" \
36  summary="The hello application from the Spring Boot guide" \
37  description="This image contains the hello application running with the Open Liberty runtime."
38
39# tag::serverXml[]
40RUN cp /opt/ol/wlp/templates/servers/springBoot3/server.xml /config/server.xml
41# end::serverXml[]
42
43# tag::cracXml[]
44COPY --chown=1001:0 src/main/liberty/instantOn/crac.xml \
45                    /config/configDropins/defaults/crac.xml
46# end::cracXml[]
47
48RUN features.sh
49
50# tag::libcache[]
51COPY --chown=1001:0 --from=staging /staging/lib.index.cache /lib.index.cache
52# end::libcache[]
53# tag::thinjar[]
54COPY --chown=1001:0 --from=staging /staging/thin-guide-spring-boot-0.1.0.jar \
55                    /config/dropins/spring/thin-guide-spring-boot-0.1.0.jar
56# end::thinjar[]
57
58RUN configure.sh 
crac.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 2<server description="Enable the org.crac API">
 3
 4    <featureManager>
 5        <!-- tag::crac[] -->
 6        <feature>crac-1.4</feature>
 7        <!-- end::crac[] -->
 8    </featureManager>
 9
10</server>
The COPY command copies the provided crac.xml configuration file to the Liberty configDropins configuration directory. The crac.xml file enables the crac feature to the Liberty instance.
Run the following command to rebuild the Docker image:
docker build -t springboot .
To take a checkpoint of the application process with the afterAppStart option, run the following command:
docker run \
  --name springBootCheckpointContainer \
  --privileged \
  --env WLP_CHECKPOINT=afterAppStart \
  springboot
When the application process checkpoint completes, the springBootCheckpointContainer application container is stopped and exits. The stopped springBootCheckpointContainer container contains the data from the InstantOn checkpoint process. Take this checkpoint process data and commit it to an application container image layer called springboot-instanton, run the following commands:
docker commit springBootCheckpointContainer springboot-instanton
docker rm springBootCheckpointContainer
The stopped springBootCheckpointContainer container is no longer needed and can safely be removed.
To verify that the InstantOn image is built, run the docker images command to list all local Docker images:
docker images
Your springboot-instanton image appears in the list of Docker images.
REPOSITORY             TAG      IMAGE ID       CREATED          SIZE
springboot-instanton   latest   c4aabcdd64bf   20 seconds ago   583MB
springboot             latest   3a5492c0cbeb   14 minutes ago   484MB
Run the springboot-instanton InstantOn application image by running the following command:
docker run \
  --rm -d \
  --name springBootContainer \
  --cap-add=CHECKPOINT_RESTORE \
  --cap-add=SETPCAP \
  --security-opt seccomp=unconfined \
  -p 9080:9080 \
  springboot-instanton
Run the following command to see the container logs:
docker logs springBootContainer
You see more logs from Spring for restoring. Liberty’s startup is complete in less than a second. It shows a faster startup time of 0.874 seconds than the original springboot image that you built in the previous section.
2024-11-22T16:33:43.349Z INFO 1027 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Restarting Spring-managed lifecycle beans after JVM restore ... 2024-11-22T16:33:43.562Z INFO 1027 --- [ecutor-thread-1] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 135784 ms 2024-11-22T16:33:43.568Z INFO 1027 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Spring-managed lifecycle restart completed (restored JVM running for 525 ms) ... CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 0.874 seconds. ... CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.897 seconds.
Go to the http://localhost:9080/hello URL to access the application.
After you are finished checking out the application, stop your container by running the following command:
docker stop springBootContainer
If you use Podman instead of Docker, you can build your InstantOn image in a simplified way. Read the Building the InstantOn image with Podman and the checkpoint.sh script documentation.
To learn more about the Liberty InstantOn feature, see the Faster startup for containerized applications with Open Liberty InstantOn documentation.
Running the application on Open Liberty
Next, you will run the Spring Boot application locally on Open Liberty by updating the pom.xml file.
The pom.xml was created for you in this directory.
Update theMaven POMfile in thestartdirectory.pom.xml
pom.xml
Add the liberty-maven-plugin to the pom.xml file.
The liberty-maven-plugin downloads and installs Open Liberty to the target/liberty directory. The installAppPackages configuration element in the pom.xml file typically takes in the following parameters: dependencies, project, or all. The default value is dependencies, but to install the Spring Boot application to Open Liberty, the value must be spring-boot-project. This value allows Maven to package, thin, and copy the guide-spring-boot-0.1.0.jar application to the Open Liberty runtime applications directory and shared library directory.
To run the Spring Boot application, the Open Liberty instance needs to be correctly configured. By default, the liberty-maven-plugin picks up the Liberty server.xml configuration file from the src/main/liberty/config directory.
Create the Libertyserver.xmlconfiguration file.src/main/liberty/config/server.xml
server.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 2<server description="new server">
 3
 4    <featureManager>
 5        <platform>jakartaee-10.0</platform>
 6    <!-- tag::servlet[] -->
 7        <feature>servlet</feature>
 8    <!-- end::servlet[] -->
 9    <!-- tag::springboot[] -->
10        <feature>springBoot-3.0</feature>
11    <!-- end::springboot[] -->
12    </featureManager>
13
14    <!-- tag::httpport[] -->
15    <httpEndpoint id="defaultHttpEndpoint"
16                  host="*"
17                  httpPort="9080"
18                  httpsPort="9443" />
19    <!-- end::httpport[] -->
20
21    <!-- tag::springBootApplication[] -->
22    <springBootApplication id="guide-spring-boot" 
23                           location="thin-guide-spring-boot-0.1.0.jar"
24                           name="guide-spring-boot" />
25    <!-- end::springBootApplication[] -->
26
27</server>
The servlet and springBoot features are required for the Liberty instance to run the Spring Boot application. The application port is specified as 9080 and the application is configured as a springBootApplication element. For more information, see the springBootApplication element documentation.
If you didn’t build the Spring Boot application, run the package goal:
WINDOWS
MAC
LINUX
mvnw.cmd package
./mvnw package
./mvnw package
Next, run the liberty:run goal. This goal creates the Open Liberty instance, installs required features, deploys the Spring Boot application to the Open Liberty instance, and starts the application.
WINDOWS
MAC
LINUX
mvnw.cmd liberty:run
./mvnw liberty:run
./mvnw liberty:run
After you see the following message, your Liberty instance is ready:
The defaultServer server is ready to run a smarter planet.
Go to the http://localhost:9080/hello URL to access the application.
After you finish exploring the application, press CTRL+C to stop the Open Liberty instance. Alternatively, you can run the liberty:stop goal from the start directory in a separate command-line session:
WINDOWS
MAC
LINUX
mvnw.cmd liberty:stop
./mvnw liberty:stop
./mvnw liberty:stop
Packaging the application embedded with Open Liberty
You can update the pom.xml file to bind more Open Liberty Maven goals to the package phase. Binding these goals to the package phase allows the Maven package goal to build a Spring Boot application that is embedded with Open Liberty.
Update the Maven POM file in thestartdirectory.pom.xml
pom.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 4    <modelVersion>4.0.0</modelVersion>
 5    <parent>
 6        <groupId>org.springframework.boot</groupId>
 7        <artifactId>spring-boot-starter-parent</artifactId>
 8        <version>3.5.6</version>
 9        <relativePath/> <!-- lookup parent from repository -->
10    </parent>
11    <groupId>com.example</groupId>
12    <artifactId>guide-spring-boot</artifactId>
13    <version>0.1.0</version>
14    <name>spring-boot-complete</name>
15    <description>Demo project for Spring Boot</description>
16
17    <properties>
18        <java.version>21</java.version>
19    </properties>
20
21    <dependencies>
22        <dependency>
23            <groupId>org.springframework.boot</groupId>
24            <artifactId>spring-boot-starter-web</artifactId>
25        </dependency>
26
27        <dependency>
28            <groupId>org.springframework.boot</groupId>
29            <artifactId>spring-boot-starter-actuator</artifactId>
30        </dependency>
31
32        <dependency>
33            <groupId>org.springframework.boot</groupId>
34            <artifactId>spring-boot-starter-test</artifactId>
35            <scope>test</scope>
36        </dependency>
37    </dependencies>
38
39    <build>
40        <plugins>
41            <plugin>
42                <groupId>org.springframework.boot</groupId>
43                <artifactId>spring-boot-maven-plugin</artifactId>
44            </plugin>
45
46      <!-- Enable Liberty Maven plugin -->
47      <!-- tag::libertyMavenPlugin[] -->
48      <plugin>
49        <groupId>io.openliberty.tools</groupId>
50        <artifactId>liberty-maven-plugin</artifactId>
51        <version>3.11.5</version>
52        <configuration>
53          <!-- tag::appsDirectory[] -->
54          <appsDirectory>apps</appsDirectory>
55          <!-- end::appsDirectory[] -->
56          <!-- tag::installAppPackages[] -->
57          <installAppPackages>spring-boot-project</installAppPackages>
58          <!-- end::installAppPackages[] -->
59          <!-- tag::include[] -->
60          <include>minify,runnable</include>
61          <!-- end::include[] -->
62          <!-- tag::packageFile[] -->
63          <packageName>GSSpringBootApp</packageName>
64          <!-- end::packageFile[] -->
65        </configuration>
66        <!-- tag::packageGoals[] -->
67        <executions>
68          <execution>
69            <id>package-server</id>
70            <phase>package</phase>
71            <goals>
72              <goal>create</goal>
73              <goal>install-feature</goal>
74              <goal>deploy</goal>
75              <goal>package</goal>
76            </goals>
77          </execution>
78        </executions>
79        <!-- end::packageGoals[] -->
80      </plugin>
81      <!-- end::libertyMavenPlugin[] -->
82      <!-- End of Liberty Maven plugin -->
83
84        </plugins>
85    </build>
86
87</project>
Add the include and packageName configuration elements, and the executions element to the pom.xml file.
The include configuration element specifies the minify, runnable values. The runnable value allows the application to be generated as a runnable JAR file. The minify value packages only what you need from your configuration files without bundling the entire Open Liberty install.
The packageName configuration element specifies that the application is generated as a GSSpringBootApp.jar file.
The executions element specifies the required Open Liberty Maven goals to generate the application that is embedded with Open Liberty.
Next, run the Maven package goal:
WINDOWS
MAC
LINUX
mvnw.cmd package
./mvnw package
./mvnw package
Run the repackaged Spring Boot application. This JAR file was defined previously in the pom.xml file.
java -jar target/GSSpringBootApp.jar
After you see the following message, your Liberty instance is ready:
The defaultServer server is ready to run a smarter planet.
Go to the http://localhost:9080/hello URL to access the application.
When you need to stop the application, press CTRL+C.
Great work! You’re done!
You just ran a basic Spring Boot application with Open Liberty.
Guide Attribution
Containerizing, packaging, and running a Spring Boot application by Open Liberty is licensed under CC BY-ND 4.0
Prerequisites:
Great work! You're done!
What did you think of this guide?
                
                
                
            Thank you for your feedback!
What could make this guide better?
Raise an issue to share feedback
Create a pull request to contribute to this guide
Need help?
Ask a question on Stack Overflow