惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
雷峰网
雷峰网
博客园_首页
The Cloudflare Blog
Hugging Face - Blog
Hugging Face - Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
爱范儿
爱范儿
小众软件
小众软件
D
Docker
P
Proofpoint News Feed
B
Blog
Vercel News
Vercel News
B
Blog RSS Feed
U
Unit 42
月光博客
月光博客
The GitHub Blog
The GitHub Blog
Apple Machine Learning Research
Apple Machine Learning Research
Y
Y Combinator Blog
I
InfoQ
Recent Announcements
Recent Announcements

Piotr's TechBlog

Continuous Development with Claude Code on GitHub - Piotr's TechBlog Quarkus REST with Apache Camel and Keycloak - Piotr's TechBlog Deep Dive into Kafka Offset Commit with Spring Boot Claude Code Template for Spring Boot Local AI Models with LM Studio and Spring AI AI Models in Containers with RamaLama Claude Code on OpenShift with vLLM and Dev Spaces Create Apps with Claude Code on Ollama Spring AI with External MCP Servers Istio Spring Boot Library Released Startup CPU Boost in Kubernetes with In-Place Pod Resize
Speed up Java Startup with Spring Boot and Project Leyden
piotr.minkowski · 2026-03-19 · via Piotr's TechBlog

This article explains how to use the new Java features provided within Project Leyden to speed up Spring Boot application startup. Project Leyden is an OpenJDK initiative focused on making Java applications start faster, warm up quicker, and use less memory. It builds on CDS (Class Data Sharing) and Ahead-of-Time optimizations to move selected computations out of runtime and perform them earlier, reducing work during application startup and execution. It is currently in the experimental phase. So, it is not a part of the standard JDK distribution, and you should definitely not try it in production. To use it, you need the so-called early access build of the JDK, which is available here. I downloaded the latest version, which is based on an incomplete JDK 26 build.

By the way, there are two early access builds of Project Leyden right now: EA1 and EA2. In this article, I’m referring to the early access 2. You can compare both versions in the project’s release notes. Here are the release notes for EA1. On the other hand, here are the release notes for EA2. There are significant differences between the two versions, for example, in the JVM flags used.

Other Articles

On my blog, you’ll find several other articles that discuss ways to optimize Java application startup times. For example, the following article explains how to use the CRaC approach to reduce the startup time of Java applications on Kubernetes. This post, on the other hand, shows how to temporarily increase the CPU resources available to our application just while it’s starting up on Kubernetes.

If you’re interested in Java application performance, particularly in a Kubernetes environment, you can read more about it in my latest book, Hands-On Java with Kubernetes.

Source Code

Feel free to use my source code if you’d like to try it out yourself. To do that, you must clone my sample GitHub repositories used in this article. You can find them here: repository1 (Spring Boot, H2, Liquibase) and repository2 (Spring Boot, Redis). Then you should only follow my instructions.

Prerequisites

Before we begin, we need to install the JDK version provided by the Leyden project. I installed the macOS version available here. If you need a version for a different operating system, you can find it at the link I included in the introduction to this article. I assume you’re installing this version of Java solely to test Leyden’s functionality. So just extract it somewhere, and during the session, set the JAVA_HOME environment variable to its location. Here’s how it looks for me:

$ export JAVA_HOME=/opt/addons/jdk/Contents/Home
$ java --version
openjdk 26-leydenpremain 2026-03-17
OpenJDK Runtime Environment (build 26-leydenpremain+1-24)
OpenJDK 64-Bit Server VM (build 26-leydenpremain+1-24, mixed mode, sharing)

ShellSession

In the same window, let’s also check the version of Maven. It should also see the 26-leydenpremain version of Java.

$ mvn --version
Apache Maven 3.9.12 (848fbb4bf2d427b72bdb2471c22fced7ebd9a7a1)
Maven home: /opt/homebrew/Cellar/maven/3.9.12/libexec
Java version: 26-leydenpremain, vendor: Oracle Corporation, runtime: /opt/addons/jdk/Contents/Home
Default locale: en_PL, platform encoding: UTF-8
OS name: "mac os x", version: "15.7.4", arch: "aarch64", family: "mac"

ShellSession

Leyden with Spring Boot Application

Spring Boot with an in-memory database and Liquibase

Let’s begin with the spring-boot-tips repository. This application starts with the embedded, in-memory H2 database and connects to it immediately upon launch. Then it uses Liquibase to initialize the database schema. There are also some additional dependencies, such as Spring Data JPA or Springdoc OpenAPI.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-liquibase</artifactId>
</dependency>
<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  <version>3.0.2</version>
</dependency>
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>runtime</scope>
</dependency>

XML

Firstly, go to the application directory and build it with Maven:

mvn clean package -DskipTests

ShellSession

Then you can start it with Java in the standard way just to check the app’s startup time. You can see my startup time below. It takes 3 seconds to start the app and initialize an in-memory database with Liquibase.

leyden-spring-boot-aot-cache

Now, let’s start the same application with the -XX:AOTCacheOutput flag. This flag tells the JVM to generate and save an Ahead-Of-Time (AOT) compilation cache to a file during execution. It should contain the desired name of the output file.

java -XX:AOTCacheOutput=spring-boot-tips.aot -jar target/spring-boot-tips-1.3-SNAPSHOT.jar

ShellSession

After you stop the app, its AOT cache should be written to a file. You should see something similar to what I see in the logs.

Next, to run the application using the AOT cache previously saved in a file, use the -XX:AOTCache parameter specifying the file’s location on disk.

java -XX:AOTCache=spring-boot-tips.aot -jar target/spring-boot-tips-1.3-SNAPSHOT.jar

ShellSession

The app launches about a second faster than before. This example may not be entirely representative, since an in-memory database is also being launched here.

leyden-spring-boot-aot-cache-start

Improve performance with Spring AOT Cache

The result isn’t bad, but actually it’s not very impressive. However, we can still improve it significantly by using Spring Boot’s AOT cache support. Compared to the previous approach, we must perform a training run on our application with its extracted form.

$ java -Djarmode=tools -jar target/spring-boot-tips-1.3-SNAPSHOT.jar \
    extract --destination application

ShellSession

The command above extracts the main jar to the application directory and all libraries to the application/lib directory. The next step is actually the same as in the previous attempt.

$ cd application
$ java -XX:AOTCacheOutput=spring-boot-tips.aot -Dspring.context.exit=onRefresh \
    -jar spring-boot-tips-1.3-SNAPSHOT.jar

ShellSession

Now our app’s startup time looks much more impressive. We’ve gone from about 3 seconds to 0.75 seconds. At this point, I’d like to extend my heartfelt thanks to Sebastien Deleuze for bringing this Spring Boot feature to my attention.

Spring Boot with an external Redis database

Now let’s move on to the sample-spring-redis repository. This application no longer uses the in-memory database or initializes it at startup. Instead, it connects to a running Redis instance. Here’s a list of included Maven dependencies.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

XML

This repository already contains docker-compose.yml file, so you can easily run Redis on Docker with the following command:

docker compose up

ShellSession

Now you can repeat the exact same steps as for the previous app. Convert the app jar to the extracted form and start the app with the –XX:AOTCacheOutput JVM parameter.

$ java -Djarmode=tools -jar target/sample-spring-redis-1.1-SNAPSHOT.jar \
    extract --destination application

$ cd application

$ java -XX:AOTCacheOutput=sample-spring-redis.aot -Dspring.context.exit=onRefresh \
    -jar sample-spring-redis-1.1-SNAPSHOT.jar

ShellSession

It took 1.1 seconds on my laptop to start the sample-spring-redis app. After you stop the app, the AOT cache is saved to the sample-spring-redis.aot file.

Here’s the final comparison. Sample Spring Boot app starts 0.27 seconds with Project Leyden, which is around 4x faster than before (1.1 seconds). Not bad 🙂

Conclusion

My tests with Project Leyden show about a 75% faster startup for the Spring Boot app, which is a solid improvement. Similar results have already been achieved with solutions like CRaC, for example, in Azul’s JVM. Of course, the benefit of Project Leyden is that it can be included as a standard in the OpenJDK distribution. However, in practice, the biggest gains for startups still come from GraalVM and its native-image approach. On the other hand, the Leyden project does not require as long a build time or as many resources as a native build does.