Blogg

Här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad, följ oss på LinkedIn

Callista medarbetare Magnus Larsson

Upgrade to Spring Boot 3.2 and Java 21 to get support for Virtual Threads and CRaC

// Magnus Larsson

With Spring Boot 3.2 and Spring Framework 6.1, we get support for some really exciting new features like Java 21, including Virtual threads, and shorter startup times using Coordinated Restore at Checkpoint (CRaC). In this blog post, I will use the source code in the 3rd edition of my book on building microservices with Spring Boot and describe how to upgrade it to Spring Boot 3.2 and Java 21.

Overview

The blog post is divided into the following sections:

To access the source code of the book that is updated to Spring Boot 3.2, run the following commands:

git clone https://github.com/PacktPublishing/Microservices-with-Spring-Boot-and-Spring-Cloud-Third-Edition.git
cd Microservices-with-Spring-Boot-and-Spring-Cloud-Third-Edition
git checkout SB3.2

This blog post describes how to upgrade the source code from Spring Boot 3.1. If you want to learn about how the source code was upgraded from Spring Boot 3.0, the version used in the book, to Spring Boot 3.1, see the blog post Upgrade to Spring Boot 3.1.

You can find the changes applied to upgrade the source code to Spring Boot 3.2 by comparing two folders that contain a clone of the Git-repo, one with the SB3.1 branch checked out and one with the SB3.2 branch checked out.

Let’s start by looking at the changes applied to the source code.

1. Upgrading to Spring Boot 3.2 and Java 21

To upgrade the source code from Spring Boot 3.1, the following steps have been performed:

  1. Upgrading dependencies in gradle.build
  2. Upgrading the Java version used in Dockerfile
  3. Upgrading the Gradle version in gradle-wrapper.properties
  4. Updating the Spring Boot launcher class in Dockerfile
  5. Applying a couple of workarounds for bugs
  6. Installing GraalVM-based JDK based on Java 21

Each step is described in detail in the subsections below.

1.1. Upgrading dependencies in gradle.build

The following dependencies have been upgraded in the gradle.build files:

Dependency Before After
Java 17 21
Spring Boot 3.1.4 3.2.3
Spring Cloud 2022.0.4 2023.0.1
Spring Dep Mgm plugin 1.1.3 1.1.4
springdoc-openapi 2.1.0 2.3.0
GraalVM Native plugin 0.9.27 0.9.28
Resilience4j 2.0.2 2.2.0
MapStruct 1.5.3 1.5.5

Note: The GraalVM Native plugin only concerns Chapter 23, Native-Complied Java Microservices.

In the SB3.1 branch for Spring Boot 3.1, these dependencies look as the following in the build.gradle files:

plugins {
    id 'org.springframework.boot' version '3.1.4'
    id 'io.spring.dependency-management' version '1.1.3'
    id 'org.graalvm.buildtools.native' version '0.9.27'
    id 'java'
}

sourceCompatibility = '17'

ext {
    springCloudVersion = "2022.0.4"
    resilience4jVersion = "2.0.2"
    mapstructVersion = "1.5.3.Final"
}

dependencies {
    implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.1.0'

In the SB3.2 branch for Spring Boot 3.2, the dependencies look like:

plugins {
    id 'org.springframework.boot' version '3.2.3'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'org.graalvm.buildtools.native' version '0.9.28'
    id 'java'
}

sourceCompatibility = '21'

ext {
    springCloudVersion = '2023.0.1'
    resilience4jVersion = '2.2.0'
    mapstructVersion = '1.5.5.Final'
}

dependencies {
    implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.3.0'

1.2. Upgrading the Java version used in Dockerfile

Each microservice’s Dockerfile has been updated to use Java 21 in runtime. As previously, Adoptium’s open source based build of OpenJDK, Eclipse Temurin is used. For more information, see https://adoptium.net/temurin.

In the SB3.1 branch for Spring Boot 3.1, Java 17 is used:

FROM eclipse-temurin:17.0.5_8-jre-focal as builder
...
FROM eclipse-temurin:17.0.5_8-jre-focal

In the SB3.2 branch for Spring Boot 3.2, Java 21 is used:

FROM eclipse-temurin:21.0.1_12-jre-jammy as builder
...
FROM eclipse-temurin:21.0.1_12-jre-jammy

1.3. Upgrading the Gradle version in gradle-wrapper.properties

To support Java 21, the Gradle version has to be version 8.5 or newer. For more information, see Gradle 8.5 Release Notes, full Java 21 support.

The file gradle/wrapper/gradle-wrapper.properties has been updated to specify that Gradle version 8.7 shall be used.

In the SB3.1 branch for Spring Boot 3.1, it looks like:

distributionUrl=https://services.gradle.org/distributions/gradle-7.6-bin.zip

In the SB3.2 branch for Spring Boot 3.2, it looks like:

distributionUrl=https://services.gradle.org/distributions/gradle-8.7-bin.zip

1.4. Updating the Spring Boot launcher class in Dockerfile

Since Spring Boot 3 no longer supports Java 8, Spring Boot’s “Uber Jar” loading mechanism has been rewritten in Spring Boot 3.2. For more information, see Spring Boot 3.2 Release Notes, nested jar support.

The new implementation is expected to replace the previous one transparently. However, an update of the source code is required in one case. In the Dockerfile’s ENTRYPOINT, the new launcher class (the main class) has to be specified.

In the SB3.1 branch for Spring Boot 3.1, the entry point looks like:

ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

In the SB3.2 branch for Spring Boot 3.2, the entry point looks like:

ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]

1.5. Applying a couple of workarounds for bugs

A couple of bugs were revealed while testing GrallVM’s native compiler with Spring Boot 3.2 in Chapter 23. The workarounds applied for each bug are described below.

  1. Hibernate v6.4.4 does not work when native compiled

    From the Spring Boot 3.2.3 release notes, we can read:

    ⚠️ Noteworthy

    This release upgrades to Hibernate 6.4.4.Final. While it contains a number of valuable bug fixes, it does not work correctly in a native image. If you are using GraalVM, Hibernate should be temporarily downgraded to 6.4.2.Final using the hibernate.version property.

    This affects the Review microservice only. To apply the workaround by downgrading Hibernate to v6.4.2, the following line has been added to its build.gradle file:

     ext['hibernate.version'] = '6.4.2.Final'
    
  2. A native compile hint is required for org.springframework.messaging.Message

    The Product Composite microservice can’t be native compiled using Spring Boot 3.2 unless an annotation hint is used to add reflection metadata for the class org.springframework.messaging.Message. The Message - class is added to the already existing @RegisterReflectionForBinding annotation in the ProductCompositeServiceApplication - class. It looks like:

     @RegisterReflectionForBinding({ ..., Message.class})
     public class ProductCompositeServiceApplication {
    

1.6. Installing GraalVM-based JDK based on Java 21

The CLI tool SDKMAN! is used to install a GraalVM-based JDK for Java 21. See Chapter 23 for instructions on how to install it.

The JDK is installed with the following command:

sdk install java 21.0.2-graalce

To ensure that the correct JDK is used when compiling the Java source code, run the following command before compiling:

sdk use java 21.0.2-graalce

This completes the walkthrough of the changes required; let’s wrap this blog post with a short recap on how to run the end-to-end tests to verify that everything works as expected with Spring Boot 3.2 and Java 21.

2. Running end-to-end tests

To try out the source code with Spring Boot 3.2 and Java 21, first ensure that Docker Desktop, git, jq, curl are installed. For installation instructions, see Chapters 21 and 22. Then perform the following steps:

git clone https://github.com/PacktPublishing/Microservices-with-Spring-Boot-and-Spring-Cloud-Third-Edition.git
cd Microservices-with-Spring-Boot-and-Spring-Cloud-Third-Edition
git checkout SB3.2
sdk use java 21.0.2-graalce
cd ChapterNN # NN = 04 to 23
./gradlew build
docker compose build
docker compose up -d
./test-em-all.bash

Note: Replace ChapterNN with Chapter04 - Chapter23 depending on what chapter you want to test.

Look for a final log message that says:

End, all tests OK...

Wrap up the tests by tearing down the microservice landscape with the command:

docker compose down

For testing the source code changes with Kubernetes, Istio, and the EFK Stack, see instructions in chapters 17 - 20 for setting up the Kubernetes cluster. For building native images with the source code changes, see instructions in Chapter 23, Native-Complied Java Microservices.

3. Summary

In this blog post, we have seen how to upgrade the source code in the book to Spring Boot 3.2 and Java 21 and use the end-to-end test script, test-em-all.bash to verify that everything works as expected.

In the next blog posts, I will describe how to use the new features supported by Spring Boot 3.2, such as Virtual threads in Java 21, and how to achieve shorter startup times using Coordinated Restore at Checkpoint (CRaC).

Tack för att du läser Callistas blogg.
Hjälp oss att nå ut med information genom att dela nyheter och artiklar i ditt nätverk.

Kommentarer