ServiceLoader API

dadom110

Erfahrenes Mitglied
Hallo Zusammen,

versuche mich gerade an einem kleinen Projekt mit minimalem Plugin-Konzept (also bei weitem nicht genug für OSGI&Co).

Ich habe mir für diesen Zweck die ServiceLoader API zur Rate gezogen:

Ich habe in Eclipse ein kleines MainProgramm geschrieben, das im Kern nichts anderes macht als die Services auf zu rufen:

Java:
    ServiceLoader<ExportService> exportServices = ServiceLoader.load(ExportService.class, classLoader);
    for (ExportService service : exportServices)
    {
      System.out.println(service.doExport(MainApplication.getExportData()));
    }

dazu habe ich 2 neue Eclipse-Projekte gebaut, die das entsprechende Interface implementieren und die die benötigten Dateien im Projekt beinhalten (meta-inf/services/...).

Wenn ich nun die beiden Service-Projekte als jar-Dateien exportiere und sie zum Testprogramm hinzufüge (ins lib-Verzeichnis und zum Classpath) funktioniert das ganze in Eclipse korrekt: er findet beide Services und ruft die entsprechenden Methoden auf.

Jetzt wollte ich das ganze als ein jar-exporieren.
Also das Main-Programm + die Services im "lib" Ordner. Dazu habe ich ein bisschen mit ant rum gebastelt, sodass ein jar raus komt:

+de/test.... (src des Main Programms)
+lib (enthält die beiden Service-jars)
+META-INF (entält die Manifest-Datei)

Manifest:
Code:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 16.2-b04 (Sun Microsystems Inc.)
Main-Class: de.main.MainApplication
Class-Path: lib/test1.jar lib/test2.jar

Das Programm wird korrekt ausgeführt, die Main Startet, aber er findet KEINE Services?!
Prinzipiell sollte die Class-Path Referenz aber passen, zum test habe ich im Main Programm mal eine Referenz auf einen der Services eingebaut:
Java:
    Class c = de.service.test01.service.ServiceExportImpl.class;
    System.out.println(c);
>> Funktioniert, also kann er zur Laufzeit die Klassen auflöse... nur der ServiceLoader scheint nicht zu erkennen das die beiden JAR's passende Services sind.

Jemand eine gute Idee? Danke schon mal &
Grüße
Dom
 
werden die jars von ant auch richtig zusammen gebaut?

Sieht alles korrekt aus. Struktur des MainProgramms wie oben beschrieben (packages der Klassen + lib Ordner mit Services + META-INF mit Manifest). In den Service-JARs gibt es auf oberster Ebene: META-INF/services/interfacename-file. Wobei die Service Projekte zur Zeit eh noch nicht von ant gebaut werden, das habe ich zum testen bisher immer mit eclipse-export gemacht.

Wie gesagt: wenn ich die beiden Service-JAR's nehme und direkt im Eclipse die beiden in den Classpath des Projektes einbinde und aus der IDE starte werden beide Services gefunden und aufgerufen. Wenn ich die beiden JAR's (die gleichen/selben) aber in das "große" jar mit der manifest Datei einbinde scheitert das ganze, bzw. die beiden Services werden nicht gefunden.

Grüße
Dom
 
Zuletzt bearbeitet:
Hi,

ich habe mal auf die schnelle in Mini Beispiel zusammen gebaut.

Einmal das EclipseProjekt > Funktioniert
Einmal das gepackte JAR > Funktioniert Nicht (keine Services werden gefunden)

Grüße
Dom

PS: Ich habe sogar versucht mehrer ClassLoader ab zu grasen, aber ohne Erfolg.
 

Anhänge

Hallo,

wie startest du die Anwendung? Hast du das lib Verzeichnis auch direkt neben dem jar liegen?
Ich hab mal ein Beispiel angehängt.

Code:
C:\temp\serviceLoaderTest>tree /F
Auflistung der Ordnerpfade für Volume SYSTEM
Volumeseriennummer : E012-F399
C:.
?   ServiceExample.jar
?   serviceLoaderTest.zip
?   startExample.cmd
?
????lib
        service1.jar
        service2.jar

Code:
C:\temp\serviceLoaderTest>startExample.cmd
Loading Services...
Classload...
Service One
Service Two
Classload...
Work Done!

Einen Weg jars zur Laufzeit zum Classpath hinzuzufügen findest du hier:
http://www.tutorials.de/java/358931-services-dynamisch-laden.html

Gruß Tom
 

Anhänge

Hi Thomas,

da liegt der Hase im Pfeffer:

Hast du das lib Verzeichnis auch direkt neben dem jar liegen?

Nein. Für mein Einsatzzweck hatte ich geplant ein (!) einziges Jar zu haben. Den ganzen Service-Gedanken nutze ich eigentlich nur zur modularisierung meiner Entwicklungs-Projekte, so sieht mein JAR aus was am Ende per ANT (aus allen zur Verfügung stehenden Service-Projekten und der Main-Application) zusammen gebaut wird und das alle Services BEINHALTET:

Inhalt des JAR's
Code:
????de... (class files der Main Application)
????lib
?       service1.jar
?       service2.jar
?
????META-INF
        MANIFEST.MF

Kann man auch eine solche Struktur per ServiceLoader auflösen?

Grüße
Dominik
 
Zuletzt bearbeitet:
Hallo,

Kann man auch eine solche Struktur per ServiceLoader auflösen?
dazu gibts mehrere Möglichkeiten:

1) innere jars beim start der Anwendung in ein temporäres Verzeichnis extrahieren und diese jars dann dynamisch dem Classpath hinzufügen (siehe oben)

2) Mit FatJar oder jarjar (http://code.google.com/p/jarjar/) ein großes jar generieren, dass die entsprechenden Classfiles hält. Das manifest.mf wäre dann das deines "haupt" jars. Die Dateien unter META-INF/services der inneren-jars werden dann alle in ein META-INF/services verzeichnis aufgesammelt.

3) Einen Jar-in-Jar ClassLoader verwenden ... Beispielsweise: https://bugs.eclipse.org/bugs/show_bug.cgi?id=219530


Ich würde dir Möglichkeit empfehlen. Da es sich recht einfach implementieren lässt.

Gruß Tom
 
Zurück