Wie erkenne ich Klassen zur Laufzeit im Klassenpfad, der eine definierte Schnittstelle implementiert?Ist ServiceLoader in Java 1.5 ähnlich?
ServiceLoader passt gut (ich denke, ich habe es nicht verwendet), aber ich muss es in Java 1.5 tun.
Wie erkenne ich Klassen zur Laufzeit im Klassenpfad, der eine definierte Schnittstelle implementiert?Ist ServiceLoader in Java 1.5 ähnlich?
ServiceLoader passt gut (ich denke, ich habe es nicht verwendet), aber ich muss es in Java 1.5 tun.
In Java 1.5 ist dafür nichts eingebaut. Ich habe es selbst implementiert; es ist nicht zu kompliziert. Wenn wir jedoch auf Java 6 aktualisieren, muss ich die Aufrufe meiner Implementierung durch Aufrufe an ServiceLoader
ersetzen. Ich hätte eine kleine Brücke zwischen der App und dem Loader definieren können, aber ich verwende sie nur an wenigen Stellen, und der Wrapper selbst wäre ein guter Kandidat für einen ServiceLoader.
Dies ist die Kernidee:
public <S> Iterable<S> load(Class<S> ifc) throws Exception {
ClassLoader ldr = Thread.currentThread().getContextClassLoader();
Enumeration<URL> e = ldr.getResources("META-INF/services/" + ifc.getName());
Collection<S> services = new ArrayList<S>();
while (e.hasMoreElements()) {
URL url = e.nextElement();
InputStream is = url.openStream();
try {
BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while (true) {
String line = r.readLine();
if (line == null)
break;
int comment = line.indexOf('#');
if (comment >= 0)
line = line.substring(0, comment);
String name = line.trim();
if (name.length() == 0)
continue;
Class<?> clz = Class.forName(name, true, ldr);
Class<? extends S> impl = clz.asSubclass(ifc);
Constructor<? extends S> ctor = impl.getConstructor();
S svc = ctor.newInstance();
services.add(svc);
}
}
finally {
is.close();
}
}
return services;
}
Bessere Ausnahmebehandlung als eine Übung für den Leser überlassen. Außerdem könnte die Methode so parametrisiert werden, dass sie einen ClassLoader der Wahl des Aufrufers akzeptiert.
Es gibt keine zuverlässige Möglichkeit zu wissen, welche Klassen im Klassenpfad enthalten sind. Laut seiner documentation, ServiceLoader stützt sich auf externe Dateien, um es zu sagen, welche Klassen geladen werden; Vielleicht möchten Sie dasselbe tun. Die Grundidee besteht darin, eine Datei mit dem Namen der zu ladenden Klasse (n) zu erstellen und sie dann mithilfe von Reflektion zu instantiieren.
Der ServiceLoader ist recht einfach und wurde (informell) innerhalb des JDK seit 1.3 verwendet. ServiceLoader hat es endlich zu einem erstklassigen Bürger gemacht. Es sucht einfach nach einer Ressourcendatei, die nach Ihrer Schnittstelle benannt ist, die im Wesentlichen im META-INF-Verzeichnis eines Bibliotheksjar enthalten ist.
Diese Datei enthält den Namen der zu ladenden Klasse.
Also, würden Sie eine Datei mit dem Namen haben:
META-INF/services/com.example.your.interface
und innen ist es eine einzige Zeile: com.you.your.interfaceImpl .
Anstelle von ServiceLoader, mag ich Netbeans Lookup. Es funktioniert mit 1.5 (und vielleicht 1.4).
Im Lieferumfang ist das gleiche wie ServiceLoader, und es ist trivial zu verwenden. Aber es bietet viel mehr Flexibilität.
Hier ist ein Link: http://openide.netbeans.org/lookup/
Hier ist ein Artikel über ServiceLoader, aber es erwähnt Netbeans Lookup am Boden: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
Sie ein OSGi-Framework der Verwendung gedacht?
javax.imageio.spi.ServiceRegistry
ist das Äquivalent zu früheren Java-Versionen. Es ist seit Java 1.4 verfügbar.
Es sieht nicht wie eine allgemeine Dienstklasse aus, aber es ist. Es ist sogar ein bisschen leistungsfähiger als ServiceLoader
, da es einige Kontrolle über die Reihenfolge der zurückgegebenen Anbieter und direkten Zugriff auf die Registrierung ermöglicht.
Siehe http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html
Leider
Es gibt nichts in Java gebaut 1.5 für diese ...
ist nur ein Teil der Wahrheit.
Es gibt nicht-Standard um.
http://www.docjar.com/docs/api/sun/misc/Service.html
Vorsicht, es ist kein Teil von Standard-J2SE-API ist! Es ist nicht standardmäßiger Bestandteil von Sun JDK. Sie können sich also nicht darauf verlassen, wenn Sie beispielsweise JRockit
verwenden.
Dies ist eine alte Frage, aber die andere Option ist Package Level Annotations. Siehe meine Antwort für: Find Java classes implementing an interface
Annotationen auf Paketebene sind Annotationen, die in package-info.java-Klassen enthalten sind.
JAXB verwendet dies anstelle von Service Loadern. Ich denke auch, dass es flexibler als der Service Loader ist.