Java - Dynamic Class Loading
April 3rd, 2008 Michael ClarkeIt’s been quite some time since my last post. This is down to a number of things - the first is that I’ve been really busy and so haven’t had that much time to write a blog post. The second is, with being so busy with mundane things, I’ve not really had anything worth while blogging about.
However, today I was on the phone with a friend (Anton) and our conversation slowly progressed to Dynamic Class Loading, specifically in Java. This made me remember that when I first heard about this technology (about three or four years ago) there wasn’t that much information available on the internet. So, I decided that I’d write a little (or perhaps not so little) post on how to go about getting Dynamically Loadable Classes in Java - it really is pretty easy.
The first thing you need to define is an interface for your modules. Mine is just going to be something simple that had a getText method to get some random text…
package com.michaelclarkeblog.dynamic.api;
public interface Module {
public String getText();
}
You can now compile your API…
~/src $ javac com/michaelclarkeblog/dynamic/api/Module.java ~/src $
The next thing to do is to write your main application that is going to do the module loading. Mine is going to be a simple main method that accepts a java class name as a run-time argument.
package com.michaelclarkeblog.dynamic.application; /* We must import the URLClassLoader and also our API. */ import java.net.URLClassLoader; import com.michaelclarkeblog.dynamic.api.*;
public class Application {
public static void main(String[] args) {
Module module;
if ( args.length > 0 ) {
try {
/* Create a new instance of the module.
* Think of this as:
* Module module = new Module()
* Except we're doing it at runtime
*/
String path = "com.michaelclarkeblog.dynamic.modules." + args[0];
module = (Module)Class.forName(path).getConstructor().newInstance();
/* Run the modules 'getText()' method defined in the interface. */
System.out.println(module.getText());
} catch (Exception e) {
System.err.println(e);
}
} else {
System.out.println("Usage: java application module_name\n");
}
}
}
That’s pretty painless, we can compile it now…
~/src $ javac com/michaelclarkeblog/dynamic/application/Application.java ~/src $
Now all that is left it to make our modules. I’m just going to write two, but you can write as many as you want.
package com.michaelclarkeblog.dynamic.modules;
import com.michaelclarkeblog.dynamic.api.*;
public class Mike implements Module {
public String getText() {
return "Hello from Mike's Module!\n";
}
}
package com.michaelclarkeblog.dynamic.modules;
import com.michaelclarkeblog.dynamic.api.*;
public class Another implements Module {
public String getText() {
return "Hello from Another Module!\n";
}
}
And now we compile our modules - notice that we’re NOT re-compiling the main application.
~/src $ javac com/michaelclarkeblog/dynamic/modules/*.java ~/src $
Time to run our program…
~/src $ java com.michaelclarkeblog.dynamic.application.Application Usage: java application module_name
~/src $ java com.michaelclarkeblog.dynamic.application.Application Mike Hello from Mike's Module!
~/src $ java com.michaelclarkeblog.dynamic.application.Application Another Hello from Another Module!
~/src $
Easy eh?!
I know the above doesn’t look very powerful. However, you can make some really dynamic and customisable applications with this technique where your users can even write their own modules for the application - all they need is the api/*.class files (or depending on how many you have you can jar them up)!
Tomorrow (simply because I am no tired) I’m going to post the same application and modules but written in C# and compiled using Mono under Linux. When I said earlier that it was hard to originally find this information for Java (which it appears not to be anymore) it was even harder to find this information for C#, let alone get it working properly!