Book's Code Upgrade: Migrate from Spring Boot 2.3 to 2.4

Book's Code Upgrade: Migrate from Spring Boot 2.3 to 2.4

This chapter describes how to upgrade the book’s source code to Spring Boot 2.4.0, Spring Cloud 2020.0, and Java 15.

Table of Contents

A minor update, or not?

Moving from Spring Boot 2.3.4 to 2.4.0 means we deal with a minor update (see the semantic versioning spec if you’re not familiar with the term). Why would I worry about writing a new post and publish the updated source code then?

This is a practical approach to migrating a Spring Boot project from version 2.3 to version 2.4 and Spring Cloud 2020.0. It uses the codebase from the Learn Microservices with Spring Boot book's practical example, but it's applicable to many other projects too. If you want to dive into how Spring Boot works and set up a complete microservice architecture, get a copy now. You can also visit the book's main page for more details about the contents and extra chapters.

In the book, I invite the readers to create the microservices using the Spring Initializr at If you select the latest version of Spring Boot available at the time of writing this article, 2.4.0, you’ll also get the latest version of Spring Cloud if you add any of its starters. You can try downloading the artifact through this link and checking the pom.xml file.

The latest version of Spring Cloud, 2020.0, is a major upgrade, which means it can break stuff. And it actually does. So does it a “minor change” introduced in Spring Boot 2.4.0 for embedded databases.

Let’s analyze and handle these changes one by one while we upgrade the source code of the book’s last chapter. All the code is available on GitHub (while you’re there, star it!).

Migrate to Spring Boot 2.4.0 and Java 15

First, we need to download and install the JDK version 15 in case we haven’t done that already.

Then, we update our poms. The code snippet in Listing 1 is an example of the changes we need to make, in this case for the Multiplication microservice. Check the highlighted lines.

  • I changed the version of the spring-boot-starter-parent dependency to 2.4.0. Starting with this version, Spring Boot will not include the suffix RELEASE. Note that, since we didn’t include library versions in any of our dependencies because it’s managed by Spring Boot’s dependency management, we’ll get all the library updates that Spring Boot decided to include in this new version. Check this link if you want to see the complete list.
  • The java.version property is 15, which means we’ll compile using JDK 15. Make sure you set your JAVA_HOME environment variable accordingly.
  • For easier versioning of the book repositories, I changed the microservice version from 0.0.1-SNAPSHOT to 2.4.0-SNAPSHOT. This way, I can just follow the same versioning as Spring Boot, which will drive the further upgrades.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="" xmlns:xsi=""
		<relativePath/> <!-- lookup parent from repository -->
	<description>Multiplication Microservice - Learn Microservices with Spring Boot - Upgrade 2.4.0</description>


        <!-- ... they remain the same, versions are updated because of the parent -->        

Listing 1. Upgrading Spring Boot and Java

Embedded Database (H2) credentials

Spring Boot 2.4 does bring a breaking change for the book’s projects. The default username is no longer sa, as covered in the book. What does this mean? If you already ran the projects using the Spring Boot 2.3.x version, the databases use sa as username and an empty password. Therefore, if you migrate to Spring Boot 2.4.0 and keep the same database files, you’ll get this error during the initialization of the Multiplication and the Gamification microservices:

org.h2.jdbc.JdbcSQLInvalidAuthorizationSpecException: Wrong user name or password [28000-200]

Learn Microservices with Spring Boot - Second Edition

There are two ways we can fix this:

  1. Remove all database files from the user’s home folder. Those are the files with .db extension.
  2. Change the H2 database username back to sa using Spring Boot properties. See Listing 2.
# Gives us access to the H2 database web console
# Creates the database in a file

Listing 2. Setting the database’s username to ‘sa’

You only need to do this in the Gamification and the Multiplication projects.

The book's source code with all the updates is available on GitHub: U.2.4.0. While you are there, please give it a star!

Building the apps

You can update all Spring Boot projects to the latest Spring Boot version: Multiplication, Gamification, Gateway, and Logs. However, this is only one part of the upgrade; the projects won’t work as they are at this point. You will get some errors if you try to run the apps now:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name
 'configurationPropertiesBeans' defined in class path resource [org/springframework/

The Spring Cloud Hoxton release is not compatible with Spring Boot 2.4 (nor with JDK 15), so we need to continue with the upgrade and include Spring Cloud as well.

Anyway, we wanted to upgrade Spring Cloud, so let’s see what changes we need to apply to our projects.

Migrate to Spring Cloud 2020.0 from Spring Cloud Hoxton

Note: This post has been updated on Feb 13th, 2021 to use the Spring Cloud release version, instead of the milestone.

To include the 2020.0 (Ilford) version of Spring Cloud, we need to update all our poms as shown in Listing 3.

<project xmlns="" xmlns:xsi=""
    <!-- ... -->

Listing 3. Upgrading Spring Cloud

In principle, we only need to change the Spring Cloud version property in all the pom.xml files for the projects using Spring Cloud, which are all the microservices - Multiplication, Gamification, Gateway, and Logs.

Let’s go through the needed changes to make our projects work after upgrading to this new Spring Cloud version.

The book's source code with all the updates is available on GitHub: U.2.4.0. While you are there, please give it a star!

Spring Cloud Bootstrap

When we upgrade to Spring Cloud 2020.0, we lose the bootstrap functionality because it has been removed by default. In our projects, we use the bootstrap phase with its corresponding file to adjust the settings of the Consul’s Config Server. This means our services will fail when running them in Docker containers because they can’t find the docker profile configuration we created to initialize the RabbitMQ host address. Without loading this profile, the microservices will try to reach the RabbitMQ server locally (from localhost - the container’s host).

To fix this, we have several options as documented in the release notes. In my case, I chose to add an extra dependency to all projects. See Listing 4 for the new dependency we can add to all projects using Spring Cloud to enable Bootstrap again.


Listing 4. Adding the Spring Cloud Starter Bootstrap

Alternatively, we could pass an environment variable to enable bootstrap, but this new dependency introduced with this Spring Cloud version makes it more transparent in my opinion.

Spring Cloud Consul Config - application name

As the Github user mi2shiii found out, Spring Cloud Consul Config doesn’t use anymore the to search for profile combinations after the Spring Cloud 2020.0 upgrade. It tries to find matches like application,rabbitmq-production, and we want it to be multiplication,rabbitmq-production. Check the Github issue to see the details in the logs.

The reason is that, in the book, I included the application name property in the file. With the change introduced by Spring to the bootstrap phase, this value doesn’t get loaded prior to looking for profiles. There used to be a logic to merge values from both property sources that is no longer there.

The fix is simple. Just move the properties from to This is a good practice anyway since there are processes in the bootstrap phase that require or may use the application name.

See the changes in the Pull Request.

Spring Cloud Sleuth - MDC key names

In the new release of Spring Cloud Sleuth, the legacy MDC keys such as X-B3-TraceId and X-B3-SpanId have been renamed. Now, these keys are aligned with the ones that Brave (the underlying tracing engine) uses natively.

The logs microservice refers to these traces to print a formatted message. It’s included in the Logback’s logging pattern in the logback-spring.xml file:

    [%-15marker] [%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] %highlight(%-5level) %msg%n

If we keep those values after upgrading Spring Cloud, this service will print empty strings as trace identifiers in the logs.

At a first glance, this issue looks very easy to fix. We modify the MDC key names to match the Brave’s values traceId and spanId:

    [%-15marker] [%X{traceId:-},%X{spanId:-}] %highlight(%-5level) %msg%n

However, if we follow that approach, we’ll observe that the identifiers don’t match between the services, and there isn’t any more a unique traceId for the complete process (credits to the reader mi2shiii for reporting the error). This is probably caused by a change in how the Spring’s AmqpAppender for logging purposes work. In the book, I was taking advantage of the fact that the logging appender used the same trace identifier as the rest of the process. However, that’s a bit fragile, as we just saw.

Therefore, instead of trying to make the traces match again, I created an alternative solution. Now, we embed the trace identifiers in the logged messages from the services (see Listing 6), which makes the centralized logger simpler since it just needs to print the message.

<appender name="AMQP"
        <pattern>%d{HH:mm:ss.SSS} [trace id: %X{traceId:-}, span id: %X{spanId:-}] [%t] %logger{36} - %msg</pattern>

Listing 6. Changing the logging pattern, so it contains the trace and span IDs

See the complete changes on Github’s Pull Request #4.

Upgrading the Docker image dependencies

We can also upgrade the Consul version used for the Consul configuration importer and the service registry. We’ll set it to version 1.9. See Listing 6, where the base image is now updated to consul:1.9. To avoid confusion, we can tag the Docker image we generate with this definition as consul-importer:1.9.

FROM consul:1.9
COPY ./consul-kv-docker.json /usr/src/consul/
WORKDIR /usr/src/consul
ENTRYPOINT until consul kv import @consul-kv-docker.json; do echo "Waiting for Consul"; sleep 2; done

Listing 6. Upgrading the base image of the consul importer’s Dockerfile (docker/consul folder).

The main Consul container can also use this Docker image. See Listing 7 for a fragment of the updated docker-compose.xml file.

version: "3"

  # ...  
    image: consul-importer:1.9
    # ...    
    image: consul:1.9
    # ...
    image: rabbitmq:3-management
    # ...

Listing 7. Docker Compose file with upgraded versions

Now, the Docker Compose file pulls the consul-importer:1.9 image (built and tagged by us with the Dockerfile shown in Listing 5), and the consul:1.9 image available in the public Docker registry.

Note that a newer RabbitMQ image will be pulled automatically since we used a tag that the Docker image’s maintainers move across versions (as long as the major version is 3). The 3-management tag moves over time to point to the latest 3.x.x version.

I made all the new microservice versions available from the public registry. Use the docker-compose-public.yml file to pull the new images and run the complete system:

docker $ docker-compose -f docker-compose-public.yml up
The book's source code with all the updates is available on GitHub: U.2.4.0. While you are there, please give it a star!
Learn Microservices with Spring Boot - Second Edition
Moisés Macero's Picture

About Moisés Macero

Software Developer, Architect, and Author.
Are you interested in my workshops?

Málaga, Spain