Ok, the post topic is a bit grandiose, it should have been “Development time swap of spring beans using a custom classloader”, so a few disclaimers, I am only talking about development, I am not aiming for the most optimal solution and yes I am still working on it. The blog is about an approach that comes with some code snippets. Is more of an idea implemented for a very particular problem which can be applied in a more generic way rather than an actual generic solution.

So if u r still reading…,
My project essentially uses spring for all the services, meaning there are a lot of stateless services which are only dependent on each other and are essentially looked up from a single big map (yes, am oversimplifying am not doing anything that stupid, actually use the appcontext there). I am tired of making a change like adding another private method or changing some lines and introducing new local variables and then seeing my debug hotswap crying hoarse about this new method and saying that add method is not supported by my VM or something else like that (yes, I know at least some of the complexity of how hot swap does it, what are the risks involved and why binary compatibility is such a key thing for it).

So I wrote a little classloader which loads the classes from my compile folder, creates an instance out of it. In another method refreshMyBean which I can access from any of my jsp pages, I use this classloader to create a new instance of the spring bean and then wire and inject it in the context from where I lookup all beans.

The class loader implementation is as rudimentary as


public class RefreshingClassLoader extends ClassLoader {
	private URL url;
	public RefreshingClassLoader() throws Exception {
		super(RefreshingClassLoader.class.getClassLoader());
		url = new URL("file:///");
	}
	protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
		System.out.println(name +"  "+resolve);
		// First, check if the class has already been loaded
		Class c = findLoadedClass(name);
		if (c == null) {
			if (name.indexOf() != -1) {
				c = findClass(name);
			} else {
				c = super.loadClass(name, resolve);
			}
		}
		if (resolve) {
			resolveClass(c);
		}
		return c;
	}
	protected Class findClass(String name) throws ClassNotFoundException {
		System.out.println(name);
		byte[] buffer = null;
		String path = name.replace('.', '/').concat(".class");
		String filePath = url.getPath() + File.separatorChar + path;
		buffer = readFile(filePath);
		return defineClass(name, buffer, 0, buffer.length);
	}
	private byte[] readFile(String filePath) throws ClassNotFoundException {
		try{
			FileInputStream inStream = new FileInputStream(filePath);
			int length = inStream.available();
			byte[] buffer = new byte[length];
			inStream.read(buffer, 0, length);
			return buffer;
		}catch(Exception exc) {
			throw new ClassNotFoundException("Could not do IO for "+filePath, exc);
		}
	}
}

The code for refreshing the spring bean is something like


public void refreshMyBean() {
	RefreshingClassLoader classLoader = new RefreshingClassLoader();
	Class changeClass = classLoader.loadClass(changeClassName);
	ChangedClassInterface changedInstance = (ChangedClassInterface) changeClass.newInstance();
	//now wire the spring services this guy uses into this instance
	//then put the new guy into the bean context wrapper
}

Fortunately for me, the actual code that uses this service does not keep any local copies and always looks up from the context. Obviously I can not handle changes in the interface yet, but theoretically if this invoker were to be created afresh it could get a handle on to the new interface too. One of the main advantages of most of the enterprise applications I have worked on is the coupling between the web request and the flow life. So if it is a new request, we can swap in all new versions of classes used in the flow.

Though, I call refreshBean from one of my UI pages when I make a change, this could be jmx or any other cooler thing (the coolest being direct IDE integration, just a plain ResourceDeltaVisitor in eclipse which would know the java file which was changed, would know if it was a spring bean and the mapping for it). There are other more evolved strategies like proxying which we can use for the same purpose, but that seems to lose on the debug information of the changed class.

This simple solution seems to help me save a lot of time in my development, so was just wondering if something this rudimentary would not be helpful for most people, if u think so, leave a comment. I know in this entry have not really covered the wiring and the reinjection part in more details as I have done it in a very non generic way, can make it much more generic (have done that before for something else), but need some proof that it is worth that effort (I was born with this congenital defect which makes u think every idea of yours is the next great thing, so now I wait for others to reject them before giving them my all).