Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.

If you think Java development is already slow, just wait till you add a Java Web Framework

That's right, I'm slow. What of it?

That’s right, I’m slow. What of it?


In our last couple of blog posts in this series, ‘Why HotSwap wasn’t good enough in 2001… and still isn’t today’ and ‘My class loader hates me and wants to slow me down’, we’ve explored the problem that exists in Java around reloading classes and Java resources and we’ve seen why HotSwap doesn’t go far enough. But we haven’t yet talked about what happens when we build upon Java and use frameworks, such as Spring, Hibernate, JSF, Vaadin, Grails, etc.

There’s no point in saying the Java reload/redeploy problem is fixed just because we can reload Java classes; that’s just half the story. What if someone were to add a Spring bean, or annotation? What happens in the land of Spring to that bean? Do we need to restart/redeploy the application for these types of changes too?

Well, the answer is YES!!

Framework configurations typically have a “run once” style initialisation for both the framework itself as well as the components that use the framework. So if you were to need to make a code or configuration change, your application would need to be redeployed to make use of the new code and config and use any new initialisation values. That sucks, right? There’s no point in a tool, like JRebel, if it only works half the time. Let’s now look at how ZeroTurnaround, the creators of JRebel, approached this problem years ago in order to bring balance to the Java force.

Integrating with frameworks

Frameworks don’t typically have their own classloaders. This is left to the containers they run in, such as application server classloaders. This means there’s no customisation around the class loading that needs to be done by JRebel, instead it focuses on the configurations the framework uses.

The first part is initialisation of frameworks and components when configuration changes and this is easy; we simply call the framework initialisation methods which are made available to us as public APIs. We can call these as many times as we want, reinitialising existing apps and components… Oh no, wait, I was just dreaming, those APIs don’t actually exist in real life. Let’s see what the reality is.

First of all, every framework is different, and has different initialising methods, behaviour and nuances. One thing is common though, the initialisation code comes in two flavours: Code that must be ‘run once an only once’ and code that can be called multiple times without adding abnormalities to the environment. It’s our job to understand all parts of the framework initialisation and split them into two groups.

  1. Methods which entirely contain code that can be run over and over (performance willing) are great, as to reload configuration into an existing runtime, we simply make a call to that method and the magic happens.
  2. Methods which cannot be called again and again require additional workaround code to be added to ensure the right code is executed to refresh the runtime. We don’t try to act like like frameworks, so we don’t code an equivalent initialiser, instead we add byte code to existing framework code to protect code that should only be run once, and add code that works around these restrictions to give us the same result, leading to an up-to-date runtime when a developer makes changes to their applications.

This is quite messy to implement and achieve, and constantly needs updating when the frameworks change. Remember, these *aren’t* APIs, so they can pretty much change at any time! Also there are performance requirements which we put upon ourselves to ensure we only reinitialise the minimum necessary for you to see your framework changes appear in the runtime, so for a simple addition of a Spring bean, for example, we wouldn’t want to needlessly refresh all aspects of the Spring framework.

This leads us on to the next question… how do we know what has changed? How do we know what needs to be reinitialised? The answer lies in a plugin framework that ZeroTurnaround created as part of the JRebel SDK, which is used by JRebel and exposed for others to use for their frameworks or specific requirements. This plugin will monitor the reloading of resources, and execute any desired custom code in reaction. Basically you’ll use a JRebel integration plugin to say: “After this specific kind of a resource is updated, go through these specific initialisation steps to update my application’s state.”

A typical scenario would be the following: your application is using the Spring framework. You add a new bean in your springapplicationContext.xml and wire it to other existing beans in your runtime. Without an integration plugin explicitly telling Spring what to do, this changes will not be reflected in your application’s running state without a restart. But using an integration plugin, you could for example say: “Hey, if you see that I’ve changed something in applicationContext.xml, please be kind enough to perform a full reload and framework initialisation of all my beans!”.

Show me the code!

Let’s take a look at some issues that may arise. In this example, we’ll be looking at Spring Bean initialisation problems that may arise. Here we’re going to update a bean injection in our Spring descriptor from:

 <bean id="bean" class="springapp.bean.TestBean">
  <property name="value" value="Foo"/>
 </bean>

to

 <bean id="bean" class="springapp.bean.TestBean">
  <property name="value" value="Bar"/>
 </bean>

Our Spring plugin will listen for changes to this descriptor, and upon this change, we’ll need to rewire the bean. Not all beans will be reinitialized on this kind of change, and some for example singletons are not reinitialized. Lets look at the following code:

 <bean id="lazyBean" class="springapp.bean.LazyBean" lazy-init="true" />
 <bean id="prototypeBean" class="springapp.bean.PrototypeBean" singleton="false" />

Here we have a lazy initialisation and a sinlgleton prototype bean. Neither of these bean should be reinitialized once they have gone through initialisation, so in the following code, JRebel will never drive either of the exceptions thown, in the afterPropertiesSet initialisation methods.

public class PrototypeBean implements InitializingBean {
 public void afterPropertiesSet() {
  throw new RuntimeException("this bean should not be instantiated");
 }
}

public class LazyBean implements InitializingBean {
 public void afterPropertiesSet() {
  throw new RuntimeException("this bean should not be instantiated");
 }
}

Let’s look at an example of initialisation code on a Spring bean that shouldn’t be called twice. Consider the following code:

@Component("bean")
public class CustomUrlHandlerMapping implements InitializingBean {

  @Autowired
  public SomeBean sb; 
  
  List<String> list= new ArrayList<List>();

  public void afterPropertiesSet() throws Exception {
    list.add(new BigObject());
    
    process(sb);
  }

Every time we reinitialise, we call afterPropertiesSet, because we presume that it needs to be called for any dependency changes, as SomeBean is Autowired. Every time this happens a new Object is added to an ArrayList and the current (maybe new) dependency is processed. But the consequences are as follows

  • There might be too many elements in the list (because of previous runs).
  • Whoever uses the list will spend more time on it because it is bigger.
  • Memory leaks because old object remains there.

Can we skip the afterPropertiesSet call? Well, not really because the newly autowired SomeBean needs to be processed. This is also common with EJB/JSF postConstruct methods.

More info on plugins in the JRebel SDK

A plugin is a JAR file that contains a class that implements the Plugin interface on the JRebel SDK. Give it a go yourself! We’ve written a tutorial that you can follow to create your own JRebel Plugin, so why not give it a go, and let me know how it works out in the comments below, or tweet @sjmaple.


This and all RebelLabs content is made possible because developers and enterprises love using ZeroTurnaround products (like JRebel) to make their coding experience more productive and enjoyable. If you dig free articles and other content, check out a free trial of JRebel and support the small-but-crafty RebelLabs team!

LEARN MORE ABOUT JREBEL