Tuesday, April 22, 2008

dynamic class reload

- Use different child classloader to reload the class and create new instance
- Apply proxy pattern to delegate the invocation to new instance, so that changes to the dynamic class become transparent to its caller.

// The dir contains the compiled classes.
File classesDir = new File("/temp/dynacode_classes/");

// The parent classloader
ClassLoader parentLoader = Postman.class.getClassLoader();

// Load class "sample.PostmanImpl" with our own classloader.
URLClassLoader loader1 = new URLClassLoader(
new URL[] { classesDir.toURL() }, parentLoader);
Class cls1 = loader1.loadClass("sample.PostmanImpl");
Postman postman1 = (Postman) cls1.newInstance();

* Invoke on postman1 ...
* Then PostmanImpl.java is modified and recompiled.

// Reload class "sample.PostmanImpl" with a new classloader.
URLClassLoader loader2 = new URLClassLoader(
new URL[] { classesDir.toURL() }, parentLoader);
Class cls2 = loader2.loadClass("sample.PostmanImpl");
Postman postman2 = (Postman) cls2.newInstance();

* Work with postman2 from now on ...
* Don't worry about loader1, cls1, and postman1
* they will be garbage collected automatically.

The Java reflection API includes a handy utility for creating proxies. The class java.lang.reflect.Proxy provides static methods that let you create proxy instances for any Java interface.

InvocationHandler handler = new DynaCodeInvocationHandler(...);
Postman proxy = (Postman) Proxy.newProxyInstance(
new Class[] { Postman.class },

public class DynaCodeInvocationHandler implements InvocationHandler {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// Get an instance of the up-to-date dynamic class
Object dynacode = getUpToDateInstance();

// Forward the invocation
return method.invoke(dynacode, args);

Reference link

No comments: