Ricerca…


Osservazioni

ServiceLoader può essere utilizzato per ottenere istanze di classi che estendono un determinato tipo (= servizio) specificato in un file contenuto in un file .jar . Il servizio che viene esteso / implementato è spesso un'interfaccia, ma non è necessario.

Le classi di estensione / implementazione devono fornire un costruttore di argomenti zero per ServiceLoader per istanziarle.

Per essere scoperto dal ServiceLoader un file di testo con il nome del nome di tipo completo del servizio implementato deve essere memorizzato all'interno della META-INF/services nel file jar. Questo file contiene un nome completo di una classe che implementa il servizio per riga.

Servizio logger

L'esempio seguente mostra come istanziare una classe per la registrazione tramite ServiceLoader .

Servizio

package servicetest;

import java.io.IOException;

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

Implementazioni del servizio

La seguente implementazione scrive semplicemente il messaggio su 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() {
    }

}

La seguente implementazione scrive i messaggi in un file di testo:

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

Il file META-INF/services/servicetest.Logger elenca i nomi delle implementazioni di Logger .

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

uso

Il seguente metodo main scrive un messaggio a tutti i logger disponibili. I logger vengono istanziati utilizzando 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);
        }
    }
}

Semplice esempio ServiceLoader

ServiceLoader è un meccanismo integrato semplice e facile da usare per il caricamento dinamico delle implementazioni dell'interfaccia. Con il caricatore di servizio, che fornisce mezzi per l'istanziazione (ma non il cablaggio), è possibile creare un semplice meccanismo di iniezione delle dipendenze in Java SE. Con l'interfaccia ServiceLoader e la separazione dell'implementazione diventa naturale e i programmi possono essere estesi in modo conveniente. In realtà molte API Java sono implementate in base al ServiceLoader

I concetti di base sono

  • Operativo su interfacce di servizi
  • Ottenere l'implementazione (s) del servizio tramite ServiceLoader
  • Fornire l'implementazione di servizi

Iniziamo dall'interfaccia e la accounting-api.jar in un vaso, chiamato ad esempio accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

Ora forniamo un'implementazione di tale servizio in un jar denominato accounting-impl.jar , contenente un'implementazione del servizio

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

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

  private long balanceFromDB(){
    ...
  }
}

inoltre, accounting-impl.jar contiene un file che dichiara che questo jar fornisce un'implementazione di AccountingService . Il file deve avere un percorso che inizia con META-INF/services/ e deve avere lo stesso nome del nome completo dell'interfaccia:

  • META-INF/services/example.AccountingService

Il contenuto del file è il nome completo dell'implementazione:

example.impl.DefaultAccountingService

Dato che entrambi i jar si trovano nel classpath del programma, che utilizza AccountingService , è possibile ottenere un'istanza del servizio utilizzando ServiceLauncher

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

Come il ServiceLoader è un Iterable , supporta diversi operatori di attuazione, in cui il programma può scegliere tra:

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

Si noti che quando si invoca next() verrà sempre creata una nuova istanza. Se si desidera riutilizzare un'istanza, è necessario utilizzare il metodo iterator() del ServiceLoader o del ciclo for-each, come mostrato sopra.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow