Spring Boot CDS support and Project Leyden anticipation

Engineering | Sébastien Deleuze | August 29, 2024 | ...

How can Spring Boot developers improve the runtime efficiency of their applications with minimal constraints in order to enjoy those benefits on most applications? The answer is the CDS support introduced by Spring Boot 3.3 which allows you to start your Spring Boot applications faster and consume less memory. It is based on the foundation introduced by Spring Framework 6.1 that I presented a few months ago.

A key point is that this new CDS support provides a different value proposition compared to the GraalVM native image support: the improvements you get with CDS are less dramatic than with native images on startup time for example, but they are still very significant while you can continue to use your regular JVM with very few side effects.

Spring Boot supports both CDS and GraalVM native images in a production-ready fashion and gives you the choice depending on your context and opinions.

CDS, a hidden gem in the JVM

CDS stands for Class Data Sharing, it is a mature technology already available and used in most JVM, but so far not at its full potential. To simplify, you are probably already using CDS without knowing it but only for optimizing JDK classes loading, while the classes of your application or libraries probably do not take advantage of it. To unlock that, it is required to perform a training run of your application.

You also need to fulfill a set of constraints that are easy to break without a dedicated support like Spring Boot one:

  • The very same JVM must be used.
  • The classpath must be specified as a list of JARs, and avoid the usage of directories, * wildcard characters and nested JARs.
  • The timestamps of the JARs must be preserved.
  • When using the CDS archive for the production run, the classpath must be the same as the one used to create the archive, in the same order. Additional JARs or directories can be specified at the end (but won’t be cached).

Spring Boot 3.3 unlocks this potential by providing 2 new features: self-extracting executable JAR and Buildpacks CDS support.

Self-extracting executable JAR

Directly running java -jar my-app.jar with the executable JAR is not the most efficient way to run your application on production. This is documented but most developers and operators not using Buildpacks miss that based on various discussions I had with the Spring community. And until recently, there was no real first-class feature to help.

Spring Boot 3.3 changes that and introduces the capability for an executable JAR to self-extract without requiring any external tool, just with the java command likely already available to run the application:

java -Djarmode=tools -jar my-app.jar extract --destination application

CDS file layout

You can then run your Spring Boot application more efficiently with:

java -jar application/my-app.jar

This feature has a superpower: it has been designed to fulfill CDS (and Project Leyden) constraints. So combined with Spring Framework support for CDS training runs, you can create a CDS archive for your Spring Boot application as following:

java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar application/my-app.jar

Then you can start your application with CDS enabled with:

java -XX:SharedArchiveFile=application.jsa -jar application/my-app.jar

CDS and Spring AOT activation support in Buildpacks

The self-extracting executable JAR feature combined with CDS usage is flexible but still requires quite a lot of manual steps, so Spring Boot and Buildpacks provide integrated support for CDS which:

  • Performs automatically the training run when creating the container image.
  • Extract the Spring Boot executable JAR to the CDS friendly file layout mentioned above.
  • Ship the CDS archive within the container.
  • Automatically enable CDS when running the container image.

Buildpacks CDS support

As demonstrated in the https://github.com/sdeleuze/spring-boot-cds-demo repository, it can be enabled as following with Gradle:

tasks.named("bootBuildImage") {
	environment["BP_JVM_CDS_ENABLED"] = "true"
}

Or with Maven:

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<configuration>
		<image>
			<env>
				<BP_JVM_CDS_ENABLED>true</BP_JVM_CDS_ENABLED>
			</env>
		</image>
	</configuration>
</plugin>

During the training run, the Spring beans are instantiated without starting the Spring lifecycle, so in practice the main side effect you may observe is early database interactions which can be avoided by configuring your application (or just the training run with the CDS_TRAINING_JAVA_TOOL_OPTIONS environment variable) to prevent such database interaction as documented here.

It is also possible to trigger Spring AOT activation support with the BP_SPRING_AOT_ENABLED environment variable but make sure to have those constraints in mind:

  • Enable Spring AOT in your Maven or Gradle build.
  • Potentially configure Spring AOT to use the Spring profile that will be used in the deployment environment.
  • CDS_TRAINING_JAVA_TOOL_OPTIONS and BP_SPRING_AOT_ENABLED can’t be combined.

The Spring and Buildpacks teams at Broadcom have been collaborating closely to leverage those OSS features and combine them with additional Tanzu Platform capabilities in order to provide a first-class CDS support for Cloud Foundry or Kubernetes, allowing for example training run autoconfiguration, making CDS as easy to enable as a flag with no side effects, and more platform-level capabilities are coming.

Data points

With a minimal Spring MVC Tomcat application running on a MacBook M2, we observe that the extracted application combined with CDS allows approximately 1.5x faster startup and 16% lower memory consumption compared to running the executable JAR. If we add Spring AOT to the mix, we get approximately 2x faster startup and 27% lower memory consumption.

WebMVC process startup time (ms) and RSS after startup (Mb)

We see similar improvements for Petclinic.

Petclinic process startup time (ms) and RSS after startup (Mb)

The values will obviously change on less powerful cloud instances, but you should likely observe similar improvement ratios.

Spring Boot and Project Leyden

Interestingly, the CDS friendly layout used by the new extract command described above is also designed to provide optimal performance with Project Leyden Early-Access builds which can be seen as a CDS successor with additional capabilities allowing:

  • Even faster startup.
  • Smaller container images (by removing the CDS archive of the JDK to keep only the application one).
  • Ahead-Of-Time warmup to have better performance after startup and reach peak performance faster.

We observe for now approximately 3x faster startup on Spring Boot applications with Project Leyden and 4x faster startup when combining Project Leyden and Spring AOT.

Project Leyden data points

I will share more in the upcoming Project Leyden talk at Devoxx Belgium 2024 that I will have the pleasure to co-present with Per Minborg from the Java Platform team.

Get the Spring newsletter

Stay connected with the Spring newsletter

Subscribe

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all