You want to load classes dynamically, just like browsers load your applets and web servers load your servlets.
Suppose you are using Java as an extension language in a larger application and want customer developers to be able to write Java classes that can run in the context of your application. You would probably want to define a small set of methods that these extension programs would have, and that you could call for such purposes as initialization, operation, and termination. The best way to do this is, of course, to publish a given possibly abstract class that provides those methods, and get the developers to subclass from it. Sound familiar? It should. This is just how web browsers such as Netscape allow the deployment of applets.
We’ll leave the thornier issues of security and of loading a
class file over a network socket for now, and assume that the user
can install the classes into the application directory or into a
directory that appears in CLASSPATH at the time the program is run.
First, let’s define our class. We’ll call it
Cooklet
(see Example 25-4), to
avoid infringing on the
overused word
applet. And we’ll initially take the
easiest path from ingredients to cookies before we complicate it.
Example 25-4. Cooklet.java
/** A simple class, just to provide the list of methods that * users need to provide to be usable in our application. * Note that the class is abstract so you must subclass it, * but the methods are non-abstract so you don't have to provide * dummy versions if you don't need a particular functionality. */ public abstract class Cooklet { /** The initialization method. The Cookie application will * call you here (AFTER calling your no-argument constructor) * to allow you to initialize your code */ public void initialize( ) { } /** The work method. The cookie application will call you * here when it is time for you to start cooking. */ public void work( ) { } /** The termination method. The cookie application will call you * here when it is time for you to stop cooking and shut down * in an orderly fashion. */ public void terminate( ) { } }
Now, since we’ll be baking, err, making this available to other people, we’ll probably want to cook up a demonstration version available too; see Example 25-5.
Example 25-5. DemoCooklet.java
public class DemoCooklet extends Cooklet { public void work( ) { System.out.println("I am busy baking cookies."); } public void terminate( ) { System.out.println("I am shutting down my ovens now."); } }
But how
does our application use it? Once we
have the name of the user’s class, we need to create a
Class
object for that class. This can be done
easily using the static method Class.forName( )
. Then we can create an instance of it
using the Class
object’s
newInstance( )
method; this will
call the class’s no-argument constructor. Then we simply cast
the newly constructed object to our Cooklet
class,
and we can call its methods! It actually takes longer to describe
this code than to look at the code, so
let’s do that now; see Example 25-6.
Example 25-6. Cookies.java
/** * This is the part of the Cookies application that loads * the user-defined subclass. */ public class Cookies { public static void main(String[] argv) { System.out.println("Cookies Application Version 0.0"); Cooklet cooklet = null; String cookletClassName = argv[0]; try { Class cookletClass = Class.forName(cookletClassName); Object cookletObject = cookletClass.newInstance( ); cooklet = (Cooklet)cookletObject; } catch (Exception e) { System.err.println("Error " + cookletClassName + e); } cooklet.initialize( ); cooklet.work( ); cooklet.terminate( ); } }
And if we run it?
$ javac Cookies DemoCooklet Cookies Application Version 0.0 I am busy baking cookies. I am shutting down my ovens now. $
Of course, this version has rather limited error handling. But you
already know how to fix that. Your ClassLoader
can
also place
classes into a package by constructing a
Package
object; you should do this if loading any
reasonable-sized set of application
classes.
3.142.133.54