Dienstag, 16. März 2010

ServiceLoader für einfache Plugins

Das dynamische nachträgliche Laden von Klassen mittels Javas Reflection ist ziemlich hacky. Der ServiceLoader nimmt einem da glücklicherweise Arbeit ab:

package serviceloader;
public class ServiceProcessor {
public void printServiceImplementations(){
ServiceLoader sl = ServiceLoader.load(Service.class);
int cnt = 0;
System.out.println("found Services:");
for(Service s : sl){
System.out.println("\t* "+s.getMessage());
cnt++;
}
System.out.println(cnt+" Service(s) found");
}

public static void main(String[] args) {
new ServiceProcessor().printServiceImplementations();
}
}

Dieses Beispiel lädt Klassen, die folgendes Interface implementieren:

package serviceloader;
public interface Service {
String getMessage();
}

Die Implementation könnte so aussehen:

package serviceloader;

public class ServiceImplementationOne implements Service{
public String getMessage() {
return this.getClass().getName();
}
}

Die Klassen, die dieses Interface wiederrum implementieren, müssen in einer Datei im Verzeichnis "META-INF/services/" eingetragen werden. Der Dateiname muss dem vollständig qualifizierenden Namen des Interface entsprechen, hier also "Service" (falls das Interface Bestandteil eines Packages ist entsprechend ".Service"). Darin befindet sich zeilenweise eingetragen die vollständigen Klassennamen:

serviceloader.ServiceImplementationOne # default Service
moreServices.ServiceImplementationTwo
moreServices.ServiceImplementationThree

Liegt alles zusammen als Jar-Files in einem Ordner sollten der jvm über die Option "-classpath" die Position der Jar-Files mitgeteilt werden:

java -classpath moreservices.jar:serviceloader.jar serviceloader.ServiceProcessor

Naja, und die Ausgabe sieht dann so aus:

found Services:
* serviceloader.ServiceImplementationOne
* moreservices.ServiceImplementationTwo
* moreservices.ServiceImplementationThree
4 Service(s) found

Ungünstig ist sicherlich, dass neue oder andere Klassen dem ServiceLoader nur über das Textfile im Jar mitgeteilt werden können. Noch flexibler sind die Plugin-Mechanismen von Netbeans oder Eclipse die dann auch Hot-Deployment und Überwachung bieten. Dafür sind diese Mechanismen aber auch ungleich komplexer. Für schnell mal ein bisschen Plugin-Fähigkeit-Gehäcke ist der ServiceLoader eigentlich eine angenehme schlanke Lösung.

Keine Kommentare: