Thursday, April 5, 2012

Class Reloading-1 Webapp in java

Imagine writing java code hit Ctrl+S and then click refresh on browser, voila the changed java code actually works!! Or in server environment you made a slight change to a class file. Wish it were loaded without require of a server restart. Or you changed some resource properties file, did you imagine that your changed resource properties file will also require a server restart. It would be nice if all web applications worked this way out of box.

Well, there is a way to make web applications reload each time it detects a change in resources. There are two ways an app server can help in reloading changes.
  • Auto-reload (Reloads the changed files and classes and then re-initialize the application, which may take another 30sec to 1 min. All the servlets that load on startup are restarted, caches cleared and reloaded. This is almost takes the same time as restarting tomcat.)
  • Hot Swap of classes - Provided by JDK class redefining without class reloading, but this works only in debug mode Java Platform Debugger Architecture (JPDA) . This can be done in tomcat running inside eclipse or other IDE. This requires tomcat to run in debug mode in eclipse). This article http://blog.redfin.com/devblog/2009/09/how_to_set_up_hot_code_replacement_with_tomcat_and_eclipse.html describes the setup of doing this with eclipse and tomcat.
  • FastSwap (websphere) only available in WebLogic (http://docs.oracle.com/cd/E15051_01/wls/docs103/deployment/deployunits.html ). This is better than Hot Swap, it is not only limited to changes in the method body. It also does not user a new classloader. I am not sure how it does the trick, I have never used it also, but wish it was there in tomcat too :( .
But there are ways to reload only specific parts of an application in tomcat without disrupting the other applications. For the curious ones I would first list down some some frameworks and tools that does class reloading.
Tools that do class reloading:



Frameworks which helps or does class reloading:Grails, play framework, tapestry, spring scripted beans, struts2 by using struts-spring-plugin, OSGi, struts2 OSGi plugin.


Non Java frameworks that does class reloading: Ruby on Rails, PHP.

Other ways to achieve class reloading:JSP - Create the full application in JSP. Of course some would say mixing views with models with controller is not a good idea. But this problem has been solved in PHP world many times. But frankly speaking if JSPs can be compiled and loaded by tomcat, why cannot tomcat load other classes? I greatly feel app servers should provide this and hope it would not be too difficult.


Oracle's PL/SQL- Make the front end generic, everything in configuration files, and push all the logic including gui validation to PL/SQL. Believe me this is possible and I have seen it. PL/SQLs can be compiled anytime.


Class Reloading Methods

(disclaimer: I am not an expert in jvm, neither I am expert in class loaders. So whatever I am going to say is based on my research of few other blogs, inspection of code struts spring plugin which does class reloading.)
Most I have seen two ways of class reloading, which are using java (a) HotSwap or (b) java ClassLoaders.
The main problems that makes class reloading hard in jvm level are bytecode optimisers and jvm JIT compiler and multi generation garbage collection. I will not go too much deep into jvm internals but I would certainly point to a blog which explains about class reloading in webapps, OSGi in general http://zeroturnaround.com/blog/rjc301/. This is another blog which discusses about why jvm hotswap is limited only to method bodies modification http://zeroturnaround.com/blog/reloading_java_classes_401_hotswap_jrebel/, this blog has a really inspiring video "A video presentation 'Do you really get class loaders' by Jevgeni Kabanov followed by a nice example of the very basic class reloading in action.

While implementing the various class reloading methods I faced some issues so I intend to show the complete setup here so that you can get a feel about it.


2. Fakereplace- Using fakereplace in a webapp is really simple. Just add the following to JAVA_OPTS in catalina.sh or catalina.bat if you are running tomcat. -javaagent:C:/Users/Samarjit/Desktop/fakereplace-parent-0.9-bin/fakereplace/fakereplace.jar -Dorg.fakereplace.packages=view
3. Simple Class Reloading - as explained by Jevgeni Kabanov in the above blog. I just created a small project in google code, which you can directly checkout and see it in action. URL: http://code.google.com/p/class-reloading-test/source/browse/#svn/trunk/ClassLoaderTest
4. Struts2 Spring plugin with class reloading- This is simple and words well out of box as per instructions. I figured out that it is using apache-commons-jci-fam. But they have integrated with springs so tightly that you will not get who is doing the trick of class reloading. After digging deep into it I decided to give apache-commons-jci-fam a try without even a sprinkle of spring. That makes my next project
5. Apache-commons-fam-jci - They have examples but those requires a bit of configuration to get them running. So I created a project that can be just checked out and run. They simulate JSP container. It reads JSP from plain text HTML then created a java source of it and compiles and finally loads the class, all of this happens on the fly and you do not need to restart your servlet container. If they can work with JSP we can apply the same to normal java classes and servlets too. URL: http://classreloadingwebapp.blogspot.com/2012/04/class-reloading-using-apache-commons.html
5. Struts2 OSGi plugin - Again this plugin seems not to be used by anyone. As there are hardly any documentation, also the plugins page does not show how to implement it with and without springs. Somehow its mixed up in the document. So I created a project completely without springs. Where you can get a feel of just the OSGi plugin. URL: http://classreloadingwebapp.blogspot.com/2012/04/class-reloading-4-using-struts2-osgi.html



3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi, First of all thank you for these arcticles about class-reloading.

    I have tried AgentSmith and Appache-Common-jci but no ne of them works for me. Could you plese help to find out what I am doing wrong?

    I have simple web application Classreload.war which is deployed to my local Tomcat. So this is my path where are web-app libraries: d:\apache-tomcat-7.0.27\webapps\Classreload\WEB-INF\lib
    One of the libraries is testClass1.jar containing one simple Class1.class which has method text() returning "1"

    In my ServletContextListener I have this code: (so what is important - this code is run once after the server start)

    ReloadingClassLoader classloader = new ReloadingClassLoader(this.getClass().getClassLoader());
    ReloadingListener listener = new ReloadingListener();
    listener.addReloadNotificationListener(classloader);
    FilesystemAlterationMonitor fam = new FilesystemAlterationMonitor();
    File f = new File("d:/apache-tomcat-7.0.27/webapps/Classreload/WEB-INF/lib");
    fam.addListener(f, listener);
    fam.start();

    Now every few second is created instance of Class1.class, called method text() and returned text is writtin into log file.
    I have re-writed testClass1.jar in d:\apache-tomcat-7.0.27\webapps\Classreload\WEB-INF\lib (while tomcat and web-app is running) whith new version which is exactly the same but the method text() returns "2". I have excpected that I would see "2" in my log now but Class1.class was not reloaded and still returns "1";

    Then I have tried the same with followed setting for AgentSmith but the same behaviour againg :-(
    Of course I had smith-1.0-jdk1.6.jar in my server libs.

    I have added this into ma catalina.bat:

    set "JAVA_OPTS=%JAVA_OPTS% -javaagent:d:\apache-tomcat-7.0.27\lib\smith-1.0-jdk1.6.jar=classes=d:\apache-tomcat-7.0.27\webapps\Classreload\WEB-INF\lib,jars=d:\apache-tomcat-7.0.27\webapps\Classreload\WEB-INF\lib,period=1000,loglevel=INFO"

    Thank you, Jakub

    ReplyDelete
  3. You may be interested in http://discotek.ca/feenix. It does class reloading and entirely free but isnt as sophisticated as JRebel.

    ReplyDelete