- 5 minutes read

The other day I mentioned that hot code replacement is broken in most Spring applications I've seen. My co-workers contradicted, claiming hot code replacement works fine. They suggested using the Spring Developer Tools to fix the problem.

Well, not quite. But I have to admit the developer tools are interesting. Interesting enough to write a blog post about it. Spoiler: instead of fixing hot code replacement, they break it. That's a pity because hot code replacement works a lot better than I expected.

Before continuing with Spring, let me quickly explain what hot code replacement is.

Hot code replacement

Hot code replacement became necessary when application servers were invented. I remember an application server that took five to ten minutes to start. As far as I remember, I first saw hot code replacement in a Java 1.3 running an IBM Websphere. It was an experimental feature that was later added to the mainstream JDK 1.4.1. By the way, if you're interested in how it works, I've found a thesis covering the invention of hot code replacement (chapter 7.2).

As you can imagine, I fought hard to update to JDK 1.4.1. Hot code replacement was attractive enough to start one or two fights.

Hot code replacement replaces code that's already running. As a developer, you've started an application, navigating several menus until you've reached the functionality you want to implement. By definition, developing means modifying the code of the functionality all the time.

Before hot code replacement, we had to restart the server. So we're back to the login screen. After that, we have to navigate to the functionality we're implementing. Adding insult to injury, every input we'd made is lost.

Hot code replacement fixes that. It replaces the methods of live objects. You correct a typo, and after hitting the F5 key in the browser, you see the result of your correction. The nice thing is that hot code replacement retains the data. The new implementation works on the data you've input before editing and compiling the method. In 2003 IDE vendors had a nice name for this feature: "fix and continue debugging."

Limits of hot code replacement

You can't modify every aspect of your code without destroying your data. The original Java implementation works if the body of a method is modified. That covers 95% of all use cases. However, if you're changing the signature of a method, hot code replacement fails. Adding a parameter to a method signature forces you to restart the application.

That's where tools like JRebel and HotswapAgent shine. They manage to save your application state even if you're adding or removing method parameters.

Hot code replacement in complex Spring applications

As things go, hot code replacement worked fine when I prepared this article. However, I know for sure it was broken in almost every Spring project I've seen at the customers'. There's a reason why they buy expensive tools like JRebel.

I can only guess. Either I'm entirely wrong, and hot code replacement was broken by another framework. Or there's a certain level of complexity that broke it. Technologies like aspect-oriented programming or byte-code manipulation might be the dealbreaker.

Be that as it may, I wrote a small application to test it, containing a REST service and a bean that's injected to it. I also tested Hibernate entities. I guess that's pretty much the level of complexity of the average Spring application, at least from the point of view of the classloader. Each time I changed a file and compiled it, the change worked without losing data. "Fix and continue debugging" is a reality.

Hot Module Reloading

The Spring Developer Tools follow a different trail. It's similar to what Angular does. They don't even try to keep and restore the data while updating the implementation. But their approach is clever, too. When you modify your source code, the developer tools restart the server - but it reloads only the files of your applications that are likely to change. Libraries, for instance, hardly ever change during development, so Spring simply keeps the old version in memory. It does a warm start that's a lot faster than a cold start. On my machine, my demo project restarted in less than a second.

If you're using something like Spring MVC, you can even add the LiveReload plugin to your browser. This reloads the page each time you're updating the source code. Usually, that brings you back to the login screen, but even so, you save an "F5" key hit. However, if you're only writing REST services, you won't benefit from this feature.

Tweaking Hot Module Reloading

Hot module reloading and LiveReload make you feel very productive. It's fun to watch the server restart in a second. Remains the problem that they break hot code replacement. Most Spring services are stateless so most developers won't notice the difference. But it's annoying if you're debugging an application with state. Stateful applications have gone out of fashion, but they're still there - just think of JSF and Spring MVC applications. You can write them stateless, but it takes extra effort to do so.

So we want to have the benefit of Hot module reloading without losing hot code replacement. Luckily, we can tweak the developer tools. The most radical approach is to add every class file to the exclude list in your application.properties file:

spring.devtools.restart.additional-exclude=**/*.class

This property is a comma-separated list of file names. If you notice several classes don't support hot code replacement, you can add all the folders that work:

# Added line feeds for legibility. # Don't use them in the application.properties file! spring.devtools.restart.additional-exclude= **/de/beyondjava/travel/itinerary/**/*.class, **/de/beyondjava/travel/expenses/**/*.class

Dig deeper

Spring documentation of the developer tools

Thesis covering the invention of hot code replacement (among many other things; browse for chapter 7.2)

HotswapAgent (an open-source project improving hot code replacement)


Comments