Sök…


Anmärkningar

ServiceLoader kan användas för att få instanser av klasser som förlänger en viss typ (= service) som anges i en fil som är packad i en .jar fil. Tjänsten som utökas / implementeras är ofta ett gränssnitt, men detta krävs inte.

Utöknings- / implementeringsklasserna måste tillhandahålla en nollargumentkonstruktör för ServiceLoader att instansera dem.

För att upptäckas av ServiceLoader en textfil med namnet på det fullständiga namnet på den implementerade tjänsten lagras i META-INF/services i burken. Den här filen innehåller ett helt kvalificerat namn på en klass som implementerar tjänsten per rad.

Logger Service

Följande exempel visar hur man initierar en klass för loggning via ServiceLoader .

Service

package servicetest;

import java.io.IOException;

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

Implementering av tjänsten

Följande implementering skriver helt enkelt meddelandet till 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() {
    }

}

Följande implementering skriver meddelandena till en textfil:

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 / tjänster / servicetest.Logger

META-INF/services/servicetest.Logger filen visar namnen på Logger implementeringarna.

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

Användande

Följande main metoden skriver ett meddelande till alla tillgängliga loggers. Loggarna instanseras med 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);
        }
    }
}

Enkelt ServiceLoader-exempel

ServiceLoader är en enkel och lättanvänd inbyggd mekanism för dynamisk lastning av gränssnittimplementeringar. Med servicelastaren - som ger medel för omedelbar inställning (men inte kablarna) - kan en enkel injektionsmekanism byggas i Java SE. Med ServiceLoader-gränssnittet och implementeringsseparationen blir naturlig och program kan bekvämt förlängas. Faktiskt implementeras en hel del Java API baserat på ServiceLoader

De grundläggande begreppen är

  • Opererar på gränssnitt mellan tjänster
  • Få implementering (er) av tjänsten via ServiceLoader
  • Tillhandahålla implementering av servics

Låt oss börja med gränssnittet och lägga det i en burk, benämnd till exempel accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

Nu tillhandahåller vi en implementering av den tjänsten i en burk med namnet accounting-impl.jar , som innehåller en implementering av tjänsten

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

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

  private long balanceFromDB(){
    ...
  }
}

vidare innehåller accounting-impl.jar en fil som förklarar att denna burk tillhandahåller en implementering av AccountingService . Filen måste ha en sökväg som börjar med META-INF/services/ och måste ha samma namn som det helt kvalificerade namnet på gränssnittet:

  • META-INF/services/example.AccountingService

Filens innehåll är det fullständiga namnet på implementeringen:

example.impl.DefaultAccountingService

Med tanke på att båda burkarna finns i klassens väg, som förbrukar AccountingService , kan en instans av tjänsten erhållas med hjälp av ServiceLauncher

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

Eftersom ServiceLoader är en Iterable , stöder den flera implementeringsleverantörer, där programmet kan välja mellan:

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

Observera att när man anropar next() en ny instans alltid att skapas. Om du vill återanvända en instans måste du använda iterator() -metoden för ServiceLoader eller för varje slinga som visas ovan.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow