Zoeken…


Opmerkingen

ServiceLoader kan worden gebruikt om instanties van klassen te krijgen die een bepaald type (= service) uitbreiden en die zijn gespecificeerd in een bestand dat is verpakt in een .jar bestand. De service die wordt uitgebreid / geïmplementeerd is vaak een interface, maar dit is niet vereist.

De uitbreidende / implementerende klassen moeten een nul-argumentconstructor bieden voor de ServiceLoader om ze te instantiëren.

Om te worden ontdekt door de ServiceLoader een tekstbestand met de naam van de volledig gekwalificeerde typenaam van de geïmplementeerde service worden opgeslagen in de META-INF/services in het jar-bestand. Dit bestand bevat één volledig gekwalificeerde naam van een klasse die de service per lijn implementeert.

Logger-service

Het volgende voorbeeld laat zien hoe u een klasse kunt instantiëren voor logboekregistratie via de ServiceLoader .

Onderhoud

package servicetest;

import java.io.IOException;

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

Implementaties van de dienst

De volgende implementatie schrijft eenvoudig het bericht naar 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() {
    }

}

De volgende implementatie schrijft de berichten naar een tekstbestand:

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

Het bestand META-INF/services/servicetest.Logger bevat de namen van de Logger implementaties.

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

Gebruik

De volgende main methode schrijft een bericht naar alle beschikbare loggers. De loggers worden geïnstantieerd met 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);
        }
    }
}

Eenvoudig ServiceLoader-voorbeeld

De ServiceLoader is een eenvoudig en gebruiksvriendelijk ingebouwd mechanisme voor het dynamisch laden van interface-implementaties. Met de servicelader - die middelen biedt voor instantatie (maar niet voor de bedrading) - kan een eenvoudig afhankelijkheidsinjectiemechanisme worden gebouwd in Java SE. Met de ServiceLoader-interface en de implementatie wordt de scheiding natuurlijk en kunnen programma's gemakkelijk worden uitgebreid. Eigenlijk zijn veel Java API's gebaseerd op de ServiceLoader

De basisconcepten zijn

  • Werkend op interfaces van diensten
  • Het verkrijgen van implementatie (s) van de service via ServiceLoader
  • Zorg voor implementatie van servics

Laten we beginnen met de interface en deze in een pot plaatsen, bijvoorbeeld accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

Nu bieden we een implementatie van die service in een pot met de naam accounting-impl.jar , met een implementatie van de service

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

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

  private long balanceFromDB(){
    ...
  }
}

verder bevat de accounting-impl.jar een bestand dat accounting-impl.jar dat dit jar een implementatie van AccountingService . Het bestand moet een pad hebben dat begint met META-INF/services/ en moet dezelfde naam hebben als de volledig gekwalificeerde naam van de interface:

  • META-INF/services/example.AccountingService

De inhoud van het bestand is de volledig gekwalificeerde naam van de implementatie:

example.impl.DefaultAccountingService

Aangezien beide potten zich in het classpath van het programma bevinden, dat de AccountingService verbruikt, kan een exemplaar van de Service worden verkregen met behulp van de ServiceLauncher

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

Aangezien de ServiceLoader een Iterable , ondersteunt het meerdere implementatieproviders, waar het programma uit kan kiezen:

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

Merk op dat bij het aanroepen van next() een nieuwe instantie wordt gemaakt. Als u een exemplaar opnieuw wilt gebruiken, moet u de iterator() -methode van de ServiceLoader of de for-each-lus gebruiken zoals hierboven weergegeven.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow