Recherche…


Remarques

ServiceLoader peut être utilisé pour obtenir des instances de classes étendant un type donné (= service) spécifié dans un fichier contenu dans un fichier .jar . Le service étendu / implémenté est souvent une interface, mais ce n'est pas obligatoire.

Les classes d'extension / implémentation doivent fournir un constructeur à argument nul pour que ServiceLoader les instancie.

Pour être découvert par ServiceLoader un fichier texte portant le nom complet du type de nom du service implémenté doit être stocké dans le META-INF/services du fichier jar. Ce fichier contient un nom qualifié complet d'une classe implémentant le service par ligne.

Service d'enregistrement

L'exemple suivant montre comment instancier une classe pour la journalisation via ServiceLoader .

Un service

package servicetest;

import java.io.IOException;

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

Implémentations du service

L'implémentation suivante écrit simplement le message sur 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() {
    }

}

L'implémentation suivante écrit les messages dans un fichier texte:

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

Le fichier META-INF/services/servicetest.Logger répertorie les noms des implémentations Logger .

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

Usage

La méthode main suivante écrit un message sur tous les enregistreurs disponibles. Les enregistreurs sont instanciés à l'aide de 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);
        }
    }
}

Exemple simple de ServiceLoader

Le ServiceLoader est un mécanisme intégré simple et facile à utiliser pour le chargement dynamique des implémentations d'interface. Avec le chargeur de service - fournissant des moyens pour l’instauration (mais pas le câblage) - un simple mécanisme d’injection de dépendance peut être intégré à Java SE. Avec l’interface ServiceLoader, la séparation de l’implémentation devient naturelle et les programmes peuvent être facilement étendus. En fait, de nombreuses API Java sont implémentées sur la base du ServiceLoader

Les concepts de base sont

  • Fonctionnant sur des interfaces de services
  • Obtention des implémentations du service via ServiceLoader
  • Mise en place de services

Commençons par l'interface et placez-la dans un pot nommé par exemple accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

Maintenant, nous fournissons une implémentation de ce service dans un jar nommé accounting-impl.jar , contenant une implémentation du service

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

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

  private long balanceFromDB(){
    ...
  }
}

De plus, le fichier accounting-impl.jar contient un fichier déclarant que ce fichier jar fournit une implémentation de AccountingService . Le fichier doit avoir un chemin commençant par META-INF/services/ et doit avoir le même nom que le nom complet de l'interface:

  • META-INF/services/example.AccountingService

Le contenu du fichier est le nom entièrement qualifié de l'implémentation:

example.impl.DefaultAccountingService

Étant donné que les deux jars se trouvent dans le chemin de classe du programme, qui utilise AccountingService , une instance du service peut être obtenue à l'aide de ServiceLauncher.

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

Comme ServiceLoader est une Iterable , il prend en charge plusieurs fournisseurs d’implémentation, parmi lesquels le programme peut choisir:

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

Notez que lors de l'appel de next() une nouvelle instance sera toujours créée. Si vous souhaitez réutiliser une instance, vous devez utiliser la méthode iterator() du ServiceLoader ou la boucle for-each, comme indiqué ci-dessus.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow