Speed Your Spring Boot 3.0 Migration

Tyler Van Gorder
|
November 28, 2022
Spring Boot migration engineering

Key Takeaways

  • Why you should upgrade your services
  • What you’ll need to update when migrating to Spring Boot 3.0
  • How OpenRewrite can help make this upgrade easier and faster
  • Where to go to learn more

Great news! Spring Boot 3.0 is now released. With it comes a host of new features that range from the ability to use new Java language features, enhanced observability, and better support for native compilation with Graal.

For many people, though, the upgrade to this latest version seems incredibly daunting. After all, there are a lot of things that need to be updated aside from Spring such as Java versions and the move to Jakarta EE 9. And it’s likely that you have many different versions of the various dependencies running across your organization, which makes the task of migrating even more difficult.

Read on to learn how to make the software migration process smoother for your entire organization.

Why you should upgrade your services

It’s easy to take an approach of “if it’s not broken, why fix it?” However, support for Spring Boot 2.x will end at the end of 2023. This means you’ll need to make all of these upgrades by then to ensure that your software remains secure when new CVEs are published. Furthermore, by upgrading, you’ll get access to a host of new features across many tools.

For example, by upgrading to Java 17, which is a requirement for Spring Boot 3.0, you’ll not only get a wide variety of new Java language features (records, pattern matching, switch expressions, etc.), but you’ll also benefit from performance improvements made to the virtual machine and garbage collector.

Note: Your environment will have a unique performance footprint. It is a good idea to use a monitoring platform to create a baseline of your applications' performance today, so you can quantify the savings when you upgrade.

In regards to Spring Boot 3.0, you can benefit from better support for building native executables and using the GraalVM. By building your Spring applications as native executables, you’ll find significant improvements in startup time. You’ll also find that observability has been a key theme in this new version, with tracing now being implemented via Micrometer Tracing

What you’ll need to update when migrating to Spring Boot 3.0 

Moving to Spring Boot 3.0 includes a number of associated migrations and dependency updates that you must do prior to migrating to this new Spring Boot version, including:

  • Upgrade your organization’s applications, infrastructure, and CI/CD pipeline to use Java 17. The good news with this step is that this work can be performed prior to upgrading any of your Spring Boot applications. 
  • Any of your existing Spring applications that leverage Java EE will require an update to Jakarta EE 9. This may seem like a straightforward exercise that involves moving all imports from the `javax` namespace to the `jakarta` namespace but this also requires that any third-party libraries also be migrated to versions that are compatible with Jakarta EE 9. 
  • Finally, depending on which version of Spring Boot your applications are being migrated from, there may be several required changes to both the application’s code and configuration when moving to Spring Boot 3.0

Java 17 migration

Spring Boot/Spring require a baseline version of Java 17 and will necessitate applications to migrate to the latest long term support (LTS) version of the Java platform.

For those applications that are running on Java 8, the key sources of friction are the introduction of the module system in Java 9 and the removal of many of the J2EE javax dependencies from the core JDK. Applications that use any of the Java EE specifications will be required to add explicit dependencies to their projects. Additionally, there are many third-party dependencies that are not compatible with the Java module system that must be upgraded as part of this exercise.

Starting with Java 11 a new, six-month release cadence was adopted by the OpenJDK community and, with it, users must now deal with deprecated APIs. Deprecated features are initially non-fatal but are later removed from the Java platform. Applications that are upgrading across multiple versions of Java will have to address the API removed from the platform. Fortunately, there is a Java tool, Jdeprscan, that can be used to identify which APIs have been deprecated or removed from the platform. Applications that are using these APIs will be required to remediate their solutions to successfully upgrade to Java 17 and beyond.

Jakarta EE 9 migration

The other big task that needs to be taken care of prior to the Spring Boot 3.0 update is the migration to J2EE 9. This is significant due to the fact that the namespace for all Java EE libraries has changed from javax to jakarta.*. As part of that, any reference to these libraries must have their packages migrated to the new namespace. 

Additionally, third-party libraries like Jackson, Hibernate, Tomcat, and Jetty provide alternate artifacts for compatibility with Jakarta EE 9. These new artifacts will require users of Sprint Boot to carefully review their third-party libraries to ensure that they have a compatible artifact.

Spring Boot migration

The 2.x line of Spring Boot was released in Feb 2018 and there have been seven minor version updates over that time. The Spring Boot team provides a migration guide for each version of Spring Boot where the most common issues are dealing with configuration changes, upgrading third-party dependencies and dealing with deprecated/removed APIs. Depending on which version of Spring Boot an application is currently running, the changes required to upgrade the application may be substantial. 

Another factor that can be challenging for organizations is that an application may use multiple sub-projects from the Spring catalog (Spring Data, Spring Batch, Spring Integration, etc.) and each of these sub-projects have their own requirements when upgrading to newer versions.

How OpenRewrite auto-refactoring can help

The good news is that the OpenRewrite community is working on recipes for many of these complex changes. This means there will be significant portions of these updates that can be automated using OpenRewrite. For those who don’t know, OpenRewrite is a semantically-aware code search and transformation tool. It is capable of making sophisticated changes to code, build files, and configurations that are idiomatically consistent with the existing project's formatting standards.

In fact, OpenRewrite already has a large catalog of recipes that can help users as they migrate to Spring Boot 3 including:

  • Migrating from older versions of Java up to Java 17
  • Migrating from Junit 4 to 5
  • Migrating from Java EE to Jakarta EE 8 and 9
  • Migrating from older versions of Spring Boot (1.5 -> 2.x, 2.7 -> 3.0) 

These recipes make coding changes, updates, and configuration changes!

Recipes are composable, which enables larger-scale framework migrations to consist of calling a set of recipes that perform specific tasks or chaining other composite recipes together. For example, the recipe to migrate to Java 11 can take advantage of recipes that modify Maven dependencies and recipes that target the migration of specific, deprecated APIs. In turn the recipe to migrate to Java 17 can be chained to the Java 11 recipe, and the Spring Boot 3.0 migration recipe can leverage those recipes along with a recipe that migrates the Jakarta EE libraries to version 9.

Let’s walk through some of the types of changes that can be automated with OpenRewrite:

OpenRewrite can intelligently make changes to existing Maven build files to upgrade dependencies.

Coding changes are made safely because of OpenRewrite’s rich AST model that allows new imports to be added (following the conventions of the existing source code) and code changes are indented properly.

And complex code changes can be made safely. In this example SimpleAuthConfig is modified to no longer extend WebSecurityConfigurerAdapter and the configure method is changed to return a new bean. The imports are adjusted, new imports are in the correct location, and formatting is consistent with the surrounding code.

There are hundreds of different recipes like these currently available on OpenRewrite, with more being added over time. It’s also possible to create your own custom recipes and then apply those recipes to your projects to perform safe, automated refactoring that will save you and your team hours of work that would normally have to be applied by hand.

Check out Moderne: migration engineering at scale

If you’re working in an enterprise environment with hundreds or thousands of repositories, manually running these recipes on each repository isn’t feasible or scalable. This is where Moderne, your continuous software modernization solution, can come in. Moderne enables you to run each of these recipes across all of your repositories in a matter of minutes—all without writing a single line of code. 

Want to learn more?

You can join the OpenRewrite Slack channel or Discord server to ask questions and interact with the community that is developing all of these recipes. Or, check out the documentation which includes more information on how to get started and what OpenRewrite can do. 

Colorful, semi-transparent Moderne symbol breaking apart like a puzzleColorful, semi-transparent Moderne symbol breaking apart like a puzzleColorful, semi-transparent Moderne symbol breaking apart like a puzzle

Back to Blog

Colorful, semi-transparent Moderne symbol breaking apart like a puzzleColorful, semi-transparent Moderne symbol breaking apart like a puzzleColorful, semi-transparent Moderne symbol breaking apart like a puzzle

Back to Engineering Blog