I prefer to think of spring framework as the raw ingredients, and Spring Boot as fully baked cake. You’re free to mix the ingredients in any way you see fit!
Spring framework always provides around 99% API backward compatibility between each version. Upgrade between Spring versions will be very straightforward as updating the version number in the pom. The 1% breaking changes are almost always deprecated rather than removed.
A new version of the Spring framework will support newer third-party dependencies like Hibernate, Jackson, Ehcache, Guava, and others. So, whenever Spring Framework is updated, these dependencies should also go through an update.
Historically external dependencies have been known to cause breaking changes in their new versions. So, If the application uses external dependencies directly in the code rather than using Spring interfaces, it will indeed be very difficult to upgrade the application.
If the application did use only Spring interfaces, the upgrade to a new version will be a 99% drop-in replacement. There will always be deprecated apis but the count will be very minuscule and the javadocs will include detailed instructions on how to upgrade from these deprecated apis.
The configuration of Spring beans through either Java or XML has been supported in all the new versions.
From XML Config to Java Config
Traditional Spring framework apps used XML for configuration, and software engineers use XML to declare dependencies and object graphs. With Spring Boot, instead of a long XML file to represent our product stack, our config is now ‘Bootiful’ type-safe Java.
Java-based config allows our IDEs to spot problems and give us warnings when our configurations don’t line up. (XML also did that, but in Java, the relationships are a little cleaner and easier to see).
This allows our team to start the product very quickly, with no need to see the entire Spring config, and no time-consuming trips down dependency rabbit holes.
The biggest hurdle in upgrading to new Spring Versions has always been hunting for the right version of third party dependencies. This pain has been alleviated now by the introduction of Spring Boot.
Spring Boot automatically handles the dependencies of the supported Spring Framework. It greatly simplifies the inclusion of external dependencies. The entirety of Spring includes great documentation for each version and provides information about deprecated changes between versions.
Boot Dictates Where Your Config Files Reside
The Spring Boot team took an opinionated approach to where the config files reside. This reduces the guesswork and effort around overriding default settings when the product moves to production (e.g. a password in prod is not the same one your developers have access to).
We had a custom-built config mechanism that managed this, but the Boot implementation is more idiomatic, so everyone on the team has consistent expectations about where config resides. It’s easier to understand and manage once you learn the convention.
Auto-Configuration in Spring Boot
Spring Boot also relies on an auto-configuration mechanism, so the many starters in the Spring Boot ecosystem are set to sensible defaults. All we have to do is override defaults with values relevant to our production infrastructure – relatively minor configuration changes only.
Spring Boot Starter Architecture and Ecosystem
The Spring Boot Starter architecture and ecosystem reduced the amount of custom code we had to maintain, particularly around common functions and services.
If the underlying infrastructure is service-oriented, it supported an easier transition to a micro-service based architecture that combines starters from the eco-system with ones built.
Modular Architecture and Ecosystem Starters
The Spring Boot Starter ecosystem gives us a huge amount of out-of-the-box functionality that traditionally we used to build ourselves. Instead of defining beans and wiring them ourselves, we’re using Spring Boot Starters wherever possible.
This allows us to build nimbly using a modular architecture, gathering starters as we need to support various services, and then assembling them together to make the final application with simple config settings.
We use the ecosystem integrations for Zookeeper, Kafka, Cassandra, JMS messaging, SMTP mail servers and many others. Historically, we’ve had to build, integrate and configure these services ourselves, but now we just drop in the necessary starter dependency, and boom: the starter is enabled and auto-configured!
If the upgrade is between consecutive versions, it is very straightforward but if the upgrade is to the latest spring major version(5.0.0) from very old Spring version(2.0.0), there will be a number of breaking changes in Spring interfaces that have to be updated properly.
Use this opportunity to remove any technical debt in code.
Paths to Upgrade
- Upgrade to the consecutive new major version branch currently supported. Fix the deprecated API calls, perform regression testing and once convinced, jump to the next supported major version.
- Introduce Spring Boot and remove the direct dependencies from the pom so that Spring Boot will handle dependencies going forward. Spring Boot automates most of the resource generation. However, you can disable the same to rather use the application specific configuration. Spring Boot documentation provides adequate information on disabling such automatic configuration.
- The DAO and hibernate template needs hibernate 4 config changes in properties. An issue with the orm shows up whenever we tried to start the server. It may fail with orm exception if you are using a session factory and hibernate template.
- Older spring cleanup jersey dependencies if they exist. It does not cause any problem, however, discard web.xml and any servlets configurations should be converted to API controllers.
- Upgrading the Spring Framework versions become very straightforward once the application is successfully migrated to Spring Boot.
- Auto-wiring happens between the component to component. Thus, the dependency management and invocations should involve components or services or entity and repository.
Use this opportunity to remove any technical debts and uplift code modularization. Reduce code duplication and dependency management issues.