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?

In the book, I invite the readers to create the microservices using the Spring Initializr at start.spring.io. If you, as a reader, 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 as if we were migrating from the source code of the last chapter in the book.

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

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="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>microservices.book</groupId>
	<artifactId>multiplication</artifactId>
	<version>2.4.0-SNAPSHOT</version>
	<name>multiplication</name>
	<description>Multiplication Microservice - Learn Microservices with Spring Boot - Upgrade 2.4.0</description>

	<properties>
		<java.version>15</java.version>
		<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
	</properties>

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

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.
spring.application.name=multiplication
# Gives us access to the H2 database web console
spring.h2.console.enabled=true
# Creates the database in a file
spring.datasource.url=jdbc:h2:file:~/multiplication;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE;
spring.datasource.username=sa

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/
cloud/autoconfigure/ConfigurationPropertiesRebinderAutoConfiguration.class]

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: At the time of writing this post, Spring Cloud 2020.0 is still in a milestone phase. I’ll update the instructions as soon as the final version is released.

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

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- ... -->
	<properties>
		<java.version>15</java.version>
		<spring-cloud.version>2020.0.0-M5</spring-cloud.version>
	</properties>
    <!-- ... -->
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

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.

Note that, given that I’m using a milestone version, I also need to add the repositories block in Listing 3 to add the location where these packages are uploaded.

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 bootstrap.properties 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.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

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 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:

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

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

Luckily, this issue is very easy to fix. We modify the MDC key names to match the Brave’s values traceId and spanId:

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

And now, the Logs microservice works perfectly again, acting as a centralized logger that consumes all the log lines from RabbitMQ with their corresponding MDC keys added by Sleuth.

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 5, 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
ENV CONSUL_HTTP_ADDR=consul:8500
ENTRYPOINT until consul kv import @consul-kv-docker.json; do echo "Waiting for Consul"; sleep 2; done

Listing 5. 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 6 for a fragment of the updated docker-compose.xml file.

version: "3"

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

Listing 6. 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?

Amsterdam, The Netherlands https://thepracticaldeveloper.com

Comments