JavaRebel has been around for quite some time now. I heard about it last year, and was hooked by the statement that it could cut development time by 6%. It’s a brave statement for any tool to make, so I had to find out more. It’s only recently that I’ve put aside the time to try this tool out and find how it actually saves me time. Before I go into this in detail, let’s see why there’s a need for productivity tools with the current Java environments.
Recently I’ve been working on a Java EE project, where I develop the project in Eclipse 3.5 and have set up Tomcat v6 as my server. It works pretty well, any changes I make while coding my JSPs get to the server pretty quickly. However, if I make a change to any of the backing beans I need to redeploy properly, not being able to rely on the default mechanism that works so well for my JSPs. How long does this redeploy take - maybe about a minute, sometimes slightly longer. The thing about this project in particular is that I’m doing it in my spare time, which I don’t have a whole lot of – those minutes I spend restarting are quite valuable to me when you add them all together.
As a desktop developer, this pattern is familiar to me. When debugging through my code in Eclipse, it’s nice to make a change and see that reflected in the running instance straight away with HotSwap. Sometimes I want to make more fundamental changes like changing the class structure, and when I do that I know I’m going to have to stop my debug instance and start again. When you’ve gone through a long series of steps to get here, this can be a killer. Without a doubt, this is one of the reasons that we fail when it comes to the “quality code vs code on time” question. I’ve often wondered why this is the case with Java when dynamic languages and .NET can handle this quickly.
Rather than give up on my language of choice and move to .NET, I’d prefer that this gets fixed for my current environment.
While there are some partial solutions available without the need for something like JavaRebel, they don't go far enough. Hot Deploy, for example, allows you to redeploy your code to an application server in about 30 seconds. That's not bad, but JavaRebel allos you to do this reload in milliseconds. HotSwap is another good solution, allowing you to change code during a debugging session but it doesn't allow major structural changes such as adding new classes or methods. Finally, OSGi is another approach to take - by splitting your application into smaller modules, it can make the redeployment seem faster.On the face of it JavaRebel seems to be the answer to all my problems here. JavaRebel is just a nice clean addition to your JVM or application server on the class loader level. With JavaRebel, it’s conceivable that I can start up my debug session and nicely interweave my code changes into the running instance, without anything unexpected happening. How does this work? Well the FAQ describes it as follows:
When a class is loaded JavaRebel will try to find a corresponding .class file for it. It will search from the classpath (including an application classpath, like WEB-INF/classes) and from the places specified in the rebel.xml configuration file. If it find a .class file JavaRebel instruments the loaded class and associates it with the found .class file. The .class file timestamp is then monitored for changes in the loaded class and updates are propagated through the extended class loader, to your application.
JavaRebel can also monitor .class files in JARs if they are specified in rebel.xml.
But the main piece to the jigsaw is:
Importantly, when loading updates to a class, JavaRebel preserves all of the existing instances of that class. This allows the application to just continue working, but also means that when adding a new instance field it will not be initialized in the existing instances, since the constructor will not be rerun.
I’m intrigued by how this works, so I contacted some of the developers at the JavaRebel team to find out more.
DZone: Great product guys. How long has JavaRebel been around?
Jevgeni Kabanov: We started development of the prototype in January 2007 and had the first internal alpha running in March. The public didn’t see it before 1.0 M2 beta, which started in October with TheServerSide and DZone announcements. The initial response was quite overwhelming and by December we fixed everything we could and released 1.0 GA. So depending on what date you pick we are either over 2 years old or just about to hit that date.
DZone: Why doesn’t this exist already in Java? And how has .NET managed to have this from day one?
Jevgeni Kabanov: This are actually two quite related questions and I’d start with the second one.
I’m not a .NET expert, but as far as I understood from looking into this and asking around, .NET doesn’t have such functionality either. The tricky part in reloading object-oriented code is preserving the object state intact. As far as I can tell .NET does not do that (e.g. in a desktop application you have to close it and navigate from scratch to see the change). However web development frameworks in .NET are designed around stateless and/or isolated classes so turnaround is usually instantaneous. However I’d assume that writing a complicated business app would run into same problem as Java at some point. Of course if there’s some .NET expert could prove me wrong, I’d only feel happy for the platform.
This also makes the reasons why this doesn’t exist in Java clearer. But the main reason, besides being plain tricky to implement, is that Java focuses heavily on performance. The need to support class code, structure and layout changes would mean significant compromises in the JVM Just-In-Time compiler. Specifically you’d have to do dependency analysis between classes and make the method lookup and calls more dynamic than they currently are. This would decrease performance, or at least further complicate the design of the JVM. These compromises are already present in dynamic languages VMs, which makes it easy to implement such features there.
DZone: Without giving away too many of your secrets, how is something like this done with Java?
Jevgeni Kabanov: We are actually doing at least three different things:
- Map the project workspace to the deployed WAR/EAR on the server so that the changes to classes and resources in the workspace would be immediately visible to the running application.
- Reload classes in the running JVM when the underlying .class files change.
- Integrate with various frameworks like Spring to make sure the changes to classes and resources are reinterpreted (e.g. new Spring dependencies are injected).
To do the first one we integrate with each application container separately. We extend their APIs with an ability to inject and override classes, resources and web resources in the running web applications. We then interpret the rebel.xml file provided by the user to override the deployed classes and resources with the ones found from the project workspace. The integration part is actually open sourced and is available from our repository for anyone interested.
To reload the actual classes we build a kind of our own Just-In-Time compiler, which intercepts loading of every class and rewrites them in a way that makes reloading possible. This involves some techniques taken from the dynamic languages virtual machines, though to make it all run fast enough on the JVM we had to do a lot of R&D.
Finally we have a plugin system with specific plugins for specific frameworks. The plugins are written in an Aspect-Oriented way (even though for performance and size reasons we use a low-level Javassist framework). Each plugin provides a Reloading aspect for a particular framework.
DZone: Could you take us through some instructions for adding JavaRebel to my development environment – either Eclipse or NetBeans?
Jevgeni Kabanov: If you use Eclipse and run the server from inside the Servers view the installation will be quite trivial. All you have to do is download JRebel distribution and install the JRebel Eclipse plugin from the Eclipse update manager. As soon as you’ve done that you’ll have a “Run with JRebel agent” in the launch configuration of all your applications and servers. Also you’ll get a “Generate rebel.xml” popup menu item if you right-click a project. Saving it to a source folder is all you need to let JRebel know your project layout. The plugin for IntelliJ IDEA has also just been released and Netbeans support is in the works. If you use Maven, we can also generate the rebel.xml file during build with a Maven plugin.
However if you run a standalone server or your setup is unusual you’ll have to do some configuration by hand. It’s described in the installation manual in three easy steps. We have also begun to release specific setup guides beginning with Apache Tomcat .
DZone: What features are you adding to JavaRebel at the moment?
Jevgeni Kabanov: The big things to look for in the next release are integration with EJB containers supporting changes to EJB interfaces, full Struts 1.x and 2.x support, better support for enums and static values plus some stuff we’d like to keep secret for the moment :)
If you’re not convinced, the ZeroTurnaround site outlines how much development time you can save with the Business Value Calculator. And Jevgeni offers a full refund to anyone who doesn’t see JavaRebel pay for itself within a month.