Ein eigener ClassLoader muss von java.lang.ClassLoader
ableiten und sollte die findClass
-Methode überschreiben. Diese Methode benötigt den vollständigen Klassennamen und gibt die geladene Klasse in Form eines Class
Objektes zurück.
Der nachfolgende ClassLoader MyClassLoader lädt die Klassen aus einem übergebenen Dateipfad. Wie in Java üblich, wird die Packagestruktur auf das Filesystem übertragen (d.h. die Klasse ch.javablog.reloadable.MyTest liegt unter ../ch/javablog/reloadable).
Im Konstruktor von MyClassLoader wird der “parent class loader” übergeben, damit der Delegationsmechanismus funktionieren kann. Erst wenn der “parent class loader” die zu ladende Klasse nicht finden konnte, wird unsere findClass-Methode aufgerufen. Dort lesen wir das “.class”-File ein und erzeugen ein byte-Feld (Zeile 23-29).
Dieses byte-Feld wird für die Methode defineClass der Oberklasse benötigt, denn sie macht die eigentliche Arbeit und generiert aus dem byte-Feld eine Java Klasse
ch.javablog.MyClassLoader:
-
public class MyClassLoader extends ClassLoader {
-
private final String startPath;
-
private final String fileSeparator = System.getProperty(“file.separator”);
-
public MyClassLoader(ClassLoader parent, String startPath) {
-
super(parent);
-
this.startPath = startPath;
-
}
-
-
protected Class findClass(String name) throws ClassNotFoundException {
-
// Absoluten Pfad zur Klasse finden
-
StringBuffer path = new StringBuffer(this.startPath);
-
String[] splittedName = name.split(“\\\\.”);
-
List splittedNameList = Arrays.asList(splittedName);
-
-
Iterator it = splittedNameList.iterator();
-
while (it.hasNext()) {
-
String pathFragment = (String) it.next();
-
path.append(fileSeparator + pathFragment);
-
}
-
path.append(“.class”);
-
System.out.println(“MyClassLoader – loading: “ + path.toString());
-
// Klasse aus Datei laden
-
File classFile = new File(path.toString());
-
int fileLength = (int) classFile.length();
-
byte[] fileContent = new byte[fileLength];
-
FileInputStream fis = null;
-
try {
-
fis = new FileInputStream(classFile);
-
fis.read(fileContent);
-
-
// Erzeugt aus dem byte Feld ein Class Object.
-
return super.defineClass(name, fileContent, 0, fileLength);
-
} catch (Exception e) {
-
throw new ClassNotFoundException(e.toString());
-
} finally {
-
if (fis != null) {
-
try {
-
fis.close();
-
} catch (Exception ignored) {
-
-
}
-
}
-
}
-
}
-
}
In einer kleinen Main-Methode probieren wir MyClassLoader
aus. Wichtig: Die Klasse ch.javablog.reloadable.MyTest
befindet sich nicht im CLASSPATH, sondern in dem Verzeichnis “myclasses” (parallel zum “classes” Verzeichnis).

ch.javablog.Main :
-
public static void main(String[] args) throws Exception{
-
ClassLoader clCurrent = Thread.currentThread().getContextClassLoader();
-
ClassLoader clNew = new MyClassLoader(clCurrent, “.” + fileSeparator + “myclasses”);
-
Class myTest = clNew.loadClass(“ch.javablog.reloadable.MyTest”);
-
System.out.println(myTest + ” classloader: “ + myTest.getClassLoader());
-
}
Ausgabe:
MyClassLoader - loading: .\myclasses\ch\javablog\reloadable\MyTest.class<br /> class ch.javablog.reloadable.MyTest classloader: ch.javablog.MyClassLoader@923e30
Interpretation:
Die MyTest
wurde erfolgreich von MyClassLoader
geladen. Wenn MyTest
weitere Klassen importiert, werden sie ebenfalls von MyClassLoader
geladen. Die untere Abbildung zeigt die Position unseres ClassLoaders in der ClassLoader-Hierarchie.

Im nächsten Teil geht es um die ClassLoader im Apache Tomcat, und warum er einen anderen Delegationsmechanismus einsetzt.