Monday, April 7, 2008

How to Hotswap classes in the running jvm?

One of the major pain of every server side java developer is that you have to redeploy your application every time you made a small change to the java classes. Now if you are working with a web application which consists 1500 classes, about 150 servlets(basically webservices), imagine how much time tomcat is gonna take to deploy or even worse redeploy that application.(it takes about 6 mins on my p4 pc). This was a small trick I learned from Masum Bhai at Therap.
JVM comes with a debugging api which actually lets you to change the defination of a class at runtime. These are the following steps you have to do.

1> Download hotswap.jar and put it in the "run-classpath" of your ant script.
2> JVM must start with debugging parameter. So add the following parameters at your java start command:
      -Xint -Xdebug -Xrunjdwp:transport=dt_socket,address=${hotswap.port},server=y,suspend=n
For example, if you are using tomcat, you can add this line at the beginning of the catalina.sh

export JAVA_OPTS="-Xint -Xms256m -Xmx256m -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n"
alternatively , you can uset the "tomcat-start" ant task given below to start your tomcat. Just make sure you have the tomcat-home ant property defined.
<property name="date-pattern" value="MM/dd/yyyy kk:mm:ss"/>
<property name="hotswap.port" value="8787"/>

<target name="compile" depends="prepare-common"

description="Compiles the application source code">

<echo message="Compiling the application source code...."/>

<!--enable timestamping upto second level (required for hotswapping)-->
<tstamp>

<format property="class.tstamp" pattern="${date-pattern}" />
</tstamp>

<javac

srcdir="${src.dir}"
destdir="${build.classes.dir}"
verbose="false" debug="true"

listfiles="false">
<!-- Use this when you want to see which files are being compiled -->
<classpath refid="run-classpath"/>
</javac>
</target>



<target name="reload" depends="compile">

<taskdef name="hotswap" classname="dak.ant.taskdefs.Hotswap">

<classpath refid="run-classpath"/>
</taskdef>

<hotswap verbose="true" port="${hotswap.port}">

<fileset dir="${build.classes.dir}" includes="**/*.class">
<date datetime="${class.tstamp}" pattern="${date-pattern}" when="after" granularity="0"/>

</fileset>
</hotswap>
</target>

<target name="tomcat-start"
description="Start Tomcat with hotswapping enabled" >


<exec executable="${tomcat.home}/bin/catalina.sh" >
<arg value="start"/>
<env key="JAVA_OPTS"

value="-Xint -Xdebug -Xrunjdwp:transport=dt_socket,address=${hotswap.port},server=y,suspend=n"/>

</exec>
</target>


The rest is simple! When you change anything in a class/group of classes, just use "ant reload" and you will see the hotswap output like this:

ant reload
Buildfile: build.xml

prepare-common:

compile:
[echo] Compiling the application source code....
[javac] Compiling 1 source file to /home/sajid/projects/cmsstandaloneportal/,tmp/cmsstandaloneportal/WEB-INF/classes

reload:
[hotswap] hotswapping 1 files from /home/sajid/projects/cmsstandaloneportal/,tmp/cmsstandaloneportal/WEB-INF/classes
[hotswap] hotswapping com.x.y.z.p.web.struts.QDispatchAction

BUILD SUCCESSFUL
Total time: 10 seconds



10 seconds! Thats all you need!

I have used this trick with Tomcat, JBoss, and standalone java applications and every time it worked like a charm! I can't tell how much deployment time it saved me. So No doubt its my most favorite ant task to date!

Note Of Caution:
Hotswapping doesn't work when you change the structure of a class (add new method/delete method/rename method). It only works when you change the logic inside a method. Thats what we do most of the time anyway, isn't it?

2 comments:

Intekhab Sadekin - Toolsmith said...

What should we use for particular changes such as adding a new method?

Sajid said...

For that you need to use "Java Rebels"