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.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow