Java Language
ServiceLoader
Suche…
Bemerkungen
ServiceLoader
können Instanzen von Klassen abgerufen werden, die einen bestimmten Typ (= Dienst) erweitern und in einer in einer .jar
Datei gepackten Datei angegeben sind. Der Dienst, der erweitert / implementiert wird, ist häufig eine Schnittstelle, dies ist jedoch nicht erforderlich.
Die Erweiterungs- / Implementierungsklassen müssen einen Null-Argument-Konstruktor für den ServiceLoader
bereitstellen, um sie zu instanziieren.
Um vom ServiceLoader
eine Textdatei mit dem Namen des vollständig qualifizierten Typnamens des implementierten META-INF/services
Verzeichnis META-INF/services
in der JAR-Datei gespeichert werden. Diese Datei enthält einen vollständig qualifizierten Namen einer Klasse, die den Dienst pro Zeile implementiert.
Logger Service
Das folgende Beispiel zeigt, wie eine Klasse für die Protokollierung über den ServiceLoader
instanziiert wird.
Bedienung
package servicetest;
import java.io.IOException;
public interface Logger extends AutoCloseable {
void log(String message) throws IOException;
}
Implementierungen des Dienstes
Die folgende Implementierung schreibt die Nachricht einfach in System.err
package servicetest.logger;
import servicetest.Logger;
public class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.err.println(message);
}
@Override
public void close() {
}
}
Die folgende Implementierung schreibt die Nachrichten in eine Textdatei:
package servicetest.logger;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import servicetest.Logger;
public class FileLogger implements Logger {
private final BufferedWriter writer;
public FileLogger() throws IOException {
writer = new BufferedWriter(new FileWriter("log.txt"));
}
@Override
public void log(String message) throws IOException {
writer.append(message);
writer.newLine();
}
@Override
public void close() throws IOException {
writer.close();
}
}
META-INF / services / servicetest.Logger
Die Datei META-INF/services/servicetest.Logger
listet die Namen der Logger
Implementierungen auf.
servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger
Verwendungszweck
Die folgende main
Methode schreibt eine Nachricht an alle verfügbaren Logger. Die Logger werden mit ServiceLoader
instanziiert.
public static void main(String[] args) throws Exception {
final String message = "Hello World!";
// get ServiceLoader for Logger
ServiceLoader<Logger> loader = ServiceLoader.load(servicetest.Logger.class);
// iterate through instances of available loggers, writing the message to each one
Iterator<Logger> iterator = loader.iterator();
while (iterator.hasNext()) {
try (Logger logger = iterator.next()) {
logger.log(message);
}
}
}
Einfaches ServiceLoader-Beispiel
Der ServiceLoader ist ein einfacher und benutzerfreundlicher integrierter Mechanismus zum dynamischen Laden von Schnittstellenimplementierungen. Mit dem Service Loader, der Mittel zur Instantiierung bereitstellt (nicht jedoch die Verdrahtung), kann in Java SE ein einfacher Abhängigkeitseinspritzungsmechanismus erstellt werden. Mit der ServiceLoader-Schnittstelle und -Implementierung wird die Trennung zur Selbstverständlichkeit und die Programme können bequem erweitert werden. Tatsächlich sind viele Java-APIs auf Basis des ServiceLoader implementiert
Die grundlegenden Konzepte sind
- Betrieb an Schnittstellen von Diensten
- Abrufen der Implementierung (en) des Dienstes über
ServiceLoader
- Bereitstellung von Diensten
Beginnen accounting-api.jar
mit der Schnittstelle und legen Sie sie in ein jar, das zum Beispiel accounting-api.jar
package example;
public interface AccountingService {
long getBalance();
}
Jetzt bieten wir eine Implementierung dieses Dienstes in einem Jar mit dem Namen accounting-impl.jar
, der eine Implementierung des Dienstes enthält
package example.impl;
import example.AccountingService;
public interface DefaultAccountingService implements AccouningService {
public long getBalance() {
return balanceFromDB();
}
private long balanceFromDB(){
...
}
}
accounting-impl.jar
enthält die accounting-impl.jar
eine Datei, die accounting-impl.jar
, dass diese Jar-Datei eine Implementierung von AccountingService
bereitstellt. Die Datei muss einen Pfad haben, der mit META-INF/services/
beginnt, und muss denselben Namen wie der vollständig qualifizierte Name der Schnittstelle haben:
-
META-INF/services/example.AccountingService
Der Inhalt der Datei ist der vollständig qualifizierte Name der Implementierung:
example.impl.DefaultAccountingService
Da sich beide Gläser im Klassenpfad des Programms befinden, das den AccountingService
, kann eine Instanz des Diensts mithilfe des ServiceLauncher abgerufen werden
ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
AccountingService service = loader.next();
long balance = service.getBalance();
Da die ServiceLoader
eine ist Iterable
unterstützt es mehrere Implementierungsanbieter, wobei das Programm von wählen:
ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
for(AccountingService service : loader) {
//...
}
Beachten Sie, dass beim Aufruf von next()
eine neue Instanz erstellt wird. Wenn Sie eine Instanz wiederverwenden möchten, müssen Sie die iterator()
Methode des ServiceLoader oder die for-each-Schleife wie oben gezeigt verwenden.