ClassLoaders sound intimidating, but if you look at the source code for one, they are
pretty simple. Basically all they do is find the class file somewhere on disk, read it into
RAM (Random Access Memory), and call java.lang.ClassLoader.defineClass tell the system
to treat ram image as legitimate byte codes. defineClass and all the other
interesting methods are protected, so you will have to write you own class that extends ClassLoader to get at them. It will all come clear if you study the source code for ClassLoader in src.zip.
There are some minor complications dealing with chaining ClassLoaders so they ask
other ClassLoaders first before going to look on their own.
The default ClassLoader can drive you nuts. Sometimes it refuses to look on the
local hard disk CLASSPATH. It won’t look in a jar other than the ones mentioned in
the <APPLET ARCHIVE ones. These archives are downloaded en masse whether you need
the files in them or not. The ClassLoader/Security system won’t let net-loaded
classes use pre-installed local DLLs. Unsigned Applets cannot use custom ClassLoaders.
Custom ClassLoaders
A custom ClassLoader is really quite simple. It need not even involve writing a new
class. You can often just instantiate one of the existing ClassLoaders. A ClassLoader needs a private byte[] loadClassData(String name) method to
find the bytes for the class somewhere, and a standard protected synchronized Class
loadClass(String name, Boolean resolve) to call your loadClassData. You inherit
everything else you need from ClassLoader.
Why would you ever want a custom ClassLoader?
- They let you change code on the fly without stopping the application. See more detail on hot code switching
below.
- They let you deal with on-the-fly byte code generated in RAM. If
you generate some byte codes in RAM and want to execute them, you can do it like this
without first creating a
- They let you deal with byte code served from a database, local or remote.
- Loading code from a cache. The code may come from a cache, or if it is not there from a remote server.
- They let you create a sandbox to control exactly what classes are loadable.
- Discourage piracy by dynamically loading frequently-changing small code snippets over the web while serving
the bulk of the app from hard disk.
- They let you deal with byte code coming from an unusual source.
- They let you dynamically change the classpath.
- They help with garbage collection. The static variables in a class and the code itself will live for
the life of the app if loaded by the default ClassLoader. If they were loaded by a
custom ClassLoader they are eligible for garbage collection once all references to
the custom ClassLoader and class are gone.
- Say you have inherited some code that uses a singleton to access a database. Now you want to use more than
one database at once. You could go through and replace all the singleton accesses with a multi-access design.
Or you could have two ClassLoader instances, each one configured for a particular
database.
- If you’ve got an intractable memory packratting problem there’s probably some static variables
involved. If you drop the ClassLoader referencing the static variables, the leaked
memory can come back. You can’t drop the instance of the default ClassLoader,
but you can drop a custom one.
- Let you encrypt your code to obfuscate it.
- Let you store your code in some non-standard form of jar.
Hot Code Changes
ClassLoaders let you modify code on the fly without shutting down an application. New
code is loaded with Class.forname. It creates new versions of the objects by
reloading the classes for the objects with a ClassLoader. You then have both old and
new versions of the same object, both with the same name, but with different data and different code. From the
JVM (Java Virtual Machine) ’s point of view, a class loaded with a new ClassLoader is a different animal
entirely from the one loaded with the standard ClassLoader even if the classes have
the same name. You can manipulate both old and new objects with a common interface.
With a new ClassLoader, you can load a different version of a class. The old
objects continue to use the old code. New objects use the new code. A given ClassLoader can load a given class only once. There is no need to unload a class. When the objects
using it are no longer referenced, the class object itself, along with the code, will be garbage collected. The
same classes, loaded by different class loaders are considered distinct classes. They are not
instanceofs each other!
You will have to instantiate a new ClassLoader every time you have a new generation
of classes. You can load all the replacement classes of a generation with the same ClassLoader. However, when you want to replace the replaced classes, you need a yet another new
ClassLoader. You can do this with multiple instances of the same ClassLoader. You only need to write one ClassLoader, perhaps not even
one, not one for each generation.
Have a look at the java.net.URLClassLoader. You may find for your given problem you
don’t even have to write whole new ClassLoader, just instantiate one of
Sun’s.
When using Applets or Java Web Start, sometimes Thread. currentThread(). getContextClassLoader(). getResource() works better than this. getClass(). getClassLoader(). getResource(). This may bypass a bug inJava version 1.4 and 1.5 now fixed in 1.6+.
Learning More
Oracle’s Javadoc on
ClassLoader class : available:
Oracle’s Javadoc on
Thread.getContextClassLoader : available:
Oracle’s Javadoc on
URLClassLoader class : available:
Oracle’s Technote Guide on
How RMI uses ClassLoaders : available:
Oracle’s Javadoc on
Class class : available: