News and Events

Upgrading to Spring Boot 2

Spring Boot 2 was released recently and the production instance of Spring Initializr ( was upgraded to Spring Boot 2 the same day.

In this post, I’d like to walk you through the process of upgrading a Spring Boot 1.x app to Spring Boot 2.

Release notes and migration guide

A good first step is to get yourself familiar with the main changes in Spring Boot 2 by reading the migration guide and the release notes.

Build upgrade

If you are using Maven and the spring-boot-starter-parent, you need to be aware that several plugins are going to be updated as part of the upgrade. If you’re not using the parent, it is worthwhile to inspect your build and upgrade the plugins that you are using. Spring Initializr is built with Maven so the easiest way is to scan spring-boot-dependencies and upgrade the plugins you are using if necessary.

Upgrade to Spring Boot 2

Initializr has dedicated auto-configuration to automatically configure the service. It also exposes dedicated metrics so it goes beyond using what already exists. The first step is to review some basic compilation errors due to renames and relocations.

In the case of Initializr, the biggest change was the move to micrometer as the CounterService and GaugeService are no longer available. Fortunately, it was quite easy to fix the compilation errors by injecting the MeterRegistry. We can then use the registry to retrieve a Counter per element to increment.

We certainly need to improve our integration with Micrometer, but that basic change is enough to get us going.

Properties migration

We haven’t looked at the test suite yet but we could give the app a go to get a first impression. Before doing so, let’s add the properties migrator to the build


Or, if you’re using Gradle:


If we run the app, it will identify the properties that are no longer managed by Spring Boot. If there is a replacement it will temporarily remap the property for you with a warning. If there isn’t a replacement, an error report will give you more information. Either way, the configuration has to be updated and the dependency removed once you have updated the configuration.

Before you move on, it is a good idea to use the search feature of your IDE to double-check that you aren’t using one of the properties you’ve migrated in an integration test. In the case of Initializr, was used and had to be migrated as well.

So the app starts now. Before going further, let’s have a look at the test suite.

Test infrastructure

As part of the upgrade, test utilities are also upgraded (we primarily use AssertJ and Mockito). AssertJ had an interesting behaviour change: containsSequence on a String stopped permitting holes in the sequence (containsSubSequence was introduced for that behavior). The Mockito upgrade was painless (ArgumentMatcher is now an interface and the import for argThat had to be changed).

We were also using PropertiesConfigurationFactory to bind a POJO to a prefix of the Environment. In 2.0, a brand new Binder API was introduced that is more flexible and easier to use. Our binding that took 10 lines of code could be reduced to 3 simple lines.

Finally, our auto-configuration tests can now benefit from ApplicationContextRunner, rather than creating the ApplicationContext and managing its lifecycle ourselves. This feature is covered in detail in a separate blog post.

We can now run the tests and realize that there are a few tests failing. The home page of the service does not work anymore in the browser! Some tests exercising the creation of build scripts via the endpoint failed too.

Mustache prefix change

The reason the templates did not render anymore is due to the fact that the prefix for Mustache templates has changed. Renaming our templates to .mustache was enough to fix that problem.

Spring MVC Path Matching Default Behavior Change

The second problem was an abuse of path matching in our endpoint. The endpoint that allows you to create a pom.xml file was as follows:

public ResponseEntity<byte[]> pom(BasicProjectRequest request) { ... }

Users are expected to call /pom.xml and that’s what we should have mapped initially. In Spring Boot 2, the Spring MVC path matching default behavior has changed so that this endpoint does not match anymore.

An easy fix is:

@RequestMapping(path = { "/pom", "/pom.xml" })
public ResponseEntity<byte[]> pom(BasicProjectRequest request) { ... }

Redirect for /info is a well-known URL to retrieve the versions mapping that Spring Initializr is currently using. It typically allows you to know which Spring Cloud version matches your current Spring Boot version.

Spring Boot 2 moves actuator endpoints to /actuator and we want to follow that default. But that does not mean we want to break a URL that users may have bookmarked. To get the best of the both worlds, we can add a simple redirect:

public WebMvcConfigurer initializrWebMvcConfigurer() {
    return new WebMvcConfigurer() {
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addRedirectViewController("/info", "/actuator/info");

Wrapping up

Migrating Spring Initializr to Spring Boot 2 was quite easy in the end. Reading the release notes and the migration guide to know beforehand the changes that may affect your app was key. Since the Spring Boot 2 release, has been happily generating tens of thousands of projects a day for the community around the World.

The next step is to properly migrate metrics to Micrometer, abandoning hierarchical names and using tags instead. Subscribe to #526 if you are interested to know more about that.

comments powered by Disqus