Szukaj…


Uwagi

ServiceLoader może służyć do uzyskiwania instancji klas rozszerzających dany typ (= usługa), które są określone w pliku spakowanym w pliku .jar . Usługa, która jest rozszerzana / wdrażana, jest często interfejsem, ale nie jest to wymagane.

Klasy rozszerzające / implementujące muszą zapewniać konstruktor zerowego argumentu, aby ServiceLoader mógł je utworzyć.

Aby zostać ServiceLoader przez ServiceLoader plik tekstowy z nazwą w pełni kwalifikowanej nazwy typu zaimplementowanej usługi musi być przechowywany w katalogu META-INF/services w pliku jar. Ten plik zawiera jedną w pełni kwalifikowaną nazwę klasy implementującej usługę w wierszu.

Usługa rejestratora

Poniższy przykład pokazuje, jak utworzyć instancję klasy do rejestrowania za pośrednictwem ServiceLoader .

Usługa

package servicetest;

import java.io.IOException;

public interface Logger extends AutoCloseable {
    
    void log(String message) throws IOException;
}

Realizacje usługi

Następująca implementacja po prostu zapisuje komunikat do 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() {
    }

}

Następująca implementacja zapisuje komunikaty w pliku tekstowym:

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

Plik META-INF/services/servicetest.Logger zawiera nazwy implementacji Logger .

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

Stosowanie

Następująca main metoda zapisuje komunikat do wszystkich dostępnych rejestratorów. Rejestratory są tworzone za pomocą ServiceLoader .

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);
        }
    }
}

Prosty przykład programu ServiceLoader

ServiceLoader jest prostym i łatwym w użyciu wbudowanym mechanizmem do dynamicznego ładowania implementacji interfejsu. Za pomocą modułu ładującego usługi - zapewniającego środki do tworzenia instancji (ale nie okablowania) - w Java SE można zbudować prosty mechanizm wstrzykiwania zależności. Dzięki interfejsowi ServiceLoader separacja implementacji staje się naturalna, a programy można wygodnie rozszerzać. W rzeczywistości wiele Java API jest implementowanych w oparciu o ServiceLoader

Podstawowe pojęcia to

  • Działanie na interfejsach usług
  • Uzyskiwanie implementacji usługi przez ServiceLoader
  • Zapewnienie wdrożenia usług

Zacznijmy od interfejsu i accounting-api.jar go do słoika o nazwie na przykład accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

Teraz zapewniamy implementację tej usługi w słoju o nazwie accounting-impl.jar , zawierającym implementację usługi

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

  public long getBalance() {
    return balanceFromDB();
  }

  private long balanceFromDB(){
    ...
  }
}

ponadto, plik accounting-impl.jar zawiera plik deklarujący, że ten jar zapewnia implementację usługi AccountingService . Plik musi mieć ścieżkę rozpoczynającą się od META-INF/services/ i musi mieć taką samą nazwę jak pełna nazwa interfejsu:

  • META-INF/services/example.AccountingService

Treść pliku to pełna nazwa nazwy implementacji:

example.impl.DefaultAccountingService

Biorąc pod uwagę, że oba słoiki znajdują się w ścieżce klas programu, który zużywa usługę AccountingService , wystąpienie usługi można uzyskać za pomocą ServiceLauncher

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
AccountingService service = loader.next();
long balance = service.getBalance();

Ponieważ ServiceLoader jest Iterable , obsługuje wielu dostawców implementacji, gdzie program może wybierać spośród:

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
for(AccountingService service : loader) {
   //...
}

Zauważ, że podczas wywoływania next() zawsze zostanie utworzone nowe wystąpienie. Jeśli chcesz ponownie użyć instancji, musisz użyć metody iterator() ServiceLoader lub pętli for-each, jak pokazano powyżej.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow