Vor kurzem habe ich MultiSPI überarbeitet, um die folgende Fallback-Logik für das Laden von Klassen hinzuzufügen: [java] if (threadContextLoader != null) { loadFromContextLoader(className); } else if (systemLoader != null) { loadFromSystemLoader(className); } else { loadFromBootstrapLoader(className); } [/java] und festgestellt, dass es nicht sofort ersichtlich ist, wie man dies auf einheitliche Weise tun kann. Aber eigentlich ist es ganz einfach... ein ClassLoader-Objekt für den Bootstrap-Loader zu erhalten ist nur ein paar Zeilen Code.
Wo liegt also das Problem?
Nun, wenn Sie mit einer wortgetreuen Implementierung des obigen Pseudocodes zufrieden sind, gibt es offensichtlich kein Problem. [java] ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) { return loader.loadClass(className); } loader = ClassLoader.getSystemClassLoader(); if (loader != null) { return loader.loadClass(className); } // null ist der Bootstrap-Loader return Class.forName(className, true, null); [/java] Aber das ist sehr prozeduraler Code1, und es wäre schon viel mehr OO, wenn wir so etwas tun könnten wie: [java] getLoader().loadClass(className); ClassLoader getLoader() { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) { return loader; } loader = ClassLoader.getSystemClassLoader(); if (loader != null) { return loader; } return ...??????? } [/java] Das Problem ist, dass es einfach keine ClassLoader.getBootstrapClassLoader() oder eine entsprechende Methode gibt. Sie können natürlich versuchen, in der übergeordneten Hierarchie des Systemladers nach oben zu gehen, aber Sie werden wahrscheinlich feststellen, dass der Bootstrap-Loader durch null repräsentiert wird - in unserem Fall nicht sehr nützlich.
BootstrapClassLoader schreiben
Was wir also wollen, ist eine ClassLoader-Implementierung, die direkt an den Bootstrap-Loader delegiert. Eine Möglichkeit wäre, loadClass zu überschreiben und einfach Class.forName mit den oben genannten Argumenten aufzurufen, aber es gibt einen noch einfacheren2 Weg: [java] class BootstrapClassLoader extends ClassLoader { BootstrapClassLoader() { /*
- Die Standardimplementierung des Classloaders verwendet den Bootstrap-Loader
- wenn es ein Null-Elternteil findet.
*/
super(null);
}
}
[/java]
Jetzt können wir unsere getLoader-Methode beenden:
[java]
// oder einfach "new ClassLoader(null) {};"
final ClassLoader BOOTSTRAP_LOADER = new BootstrapClassLoader();
ClassLoader getLoader() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader != null) {
return loader;
}
loader = ClassLoader.getSystemClassLoader();
if (loader != null) {
return loader;
}
return BOOTSTRAP_LOADER;
}
[/java]
Wenn wir nicht gerade sehr leistungsbewusst sind, können wir daraus sogar eine fast funktionale 3 machen:
[java]
ClassLoader getLoader() {
return Iterables.find(asList(Thread.currentThread().getContextClassLoader(),
ClassLoader.getSystemClassLoader(), BOOTSTRAP_LOADER), Predicates.notNull());
}
[/java]
Es gibt ein Demo-Snippet auf PasteBin pastebin.com/nJVXMucK.
Fußnoten
- Ich hoffe, Ihre unmittelbare Reaktion war so etwas wie: "Ah!
- und, meiner Meinung nach, eleganter
- Starker Einsatz von Guave voraus!
Verfasst von
Andrew Phillips
Unsere Ideen
Weitere Blogs
Contact



