Modernizing and Evolving Spring Applications - HashedIn Technologies

Modernizing and Evolving Spring Applications

Technology - 05 Jan 2017
Harish Thyagarajan

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 anyway you see fit!

Spring framework always provides around 99% API backward compatibility between each versions. 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.

New version of Spring framework will support newer third party dependencies like Hibernate, Jackson, Ehcache, Guava and others. So whenever Spring Framework is updated, these dependencies will also be needed to be updated. 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 and greatly simplifies the inclusion of external dependencies. The entirety of Spring includes great documentation for each version and provides information of 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 underlying infrastructure is service-oriented, it supported an easier transition to a microservice-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

  1. 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.
  2. 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 but the same can be disabled to rather use the application specific configuration. Spring Boot documentation provides adequate information on disabling such automatic configuration.
  3. The DAO and hibernate template needs hibernate 4 config changes in properties. Issue with with the orm shows up whenever we tried to start the server, it fails with orm exception is you are using session factory and hibernate template.
  4. Older spring cleanup jersey dependencies if they exist, it does not not cause any problem however, discard web.xml and any servlets configurations should be converted to api controllers.
  5. Once the application is successfully migrated to Spring Boot, upgrading the Spring Framework versions become very straightforward.
  6. Auto wiring happens between component to component hence dependency management and invocations should involved components or services or entity and repository.

Use this opportunity to remove any technical debts and uplift code modularisation. Reduce code duplication and dependency management issues.


E-book on Digital Business Transformation