Buscar..


Observaciones

ServiceLoader se puede usar para obtener instancias de clases que amplían un tipo dado (= servicio) que se especifican en un archivo empaquetado en un archivo .jar . El servicio que se extiende / implementa a menudo es una interfaz, pero esto no es necesario.

Las clases de extensión / implementación deben proporcionar un constructor de argumento cero para que ServiceLoader ejemplifique.

Para que ServiceLoader descubra, debe ServiceLoader un archivo de texto con el nombre del nombre de tipo completo del servicio implementado dentro del directorio META-INF/services en el archivo jar. Este archivo contiene un nombre completo de una clase que implementa el servicio por línea.

Servicio de registrador

El siguiente ejemplo muestra cómo crear una instancia de una clase para el registro a través del ServiceLoader .

Servicio

package servicetest;

import java.io.IOException;

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

Implementaciones del servicio.

La siguiente implementación simplemente escribe el mensaje en 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 siguiente implementación escribe los mensajes en un archivo de texto:

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

El archivo META-INF/services/servicetest.Logger enumera los nombres de las implementaciones de Logger .

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

Uso

El siguiente método main escribe un mensaje a todos los registradores disponibles. Los registradores se ServiceLoader instancias utilizando 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);
        }
    }
}

Ejemplo simple de ServiceLoader

El ServiceLoader es un mecanismo integrado simple y fácil de usar para la carga dinámica de implementaciones de interfaz. Con el cargador de servicios, que proporciona medios para la creación de instancias (pero no el cableado), se puede construir un mecanismo de inyección de dependencia simple en Java SE. Con la interfaz y la implementación de ServiceLoader, la separación se vuelve natural y los programas se pueden extender convenientemente. En realidad, una gran cantidad de API de Java están implementadas basadas en el ServiceLoader

Los conceptos básicos son

  • Operando en interfaces de servicios
  • Obtención de implementaciones del servicio a través de ServiceLoader
  • Proporcionando implementación de servicios

Comencemos con la interfaz y la pongamos en un jar, llamado, por ejemplo, accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

Ahora proporcionamos una implementación de ese servicio en un jar llamado accounting-impl.jar , que contiene una implementación del servicio

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

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

  private long balanceFromDB(){
    ...
  }
}

Además, accounting-impl.jar contiene un archivo que declara que este contenedor proporciona una implementación de AccountingService . El archivo debe tener una ruta que comience con META-INF/services/ y debe tener el mismo nombre que el nombre completo de la interfaz:

  • META-INF/services/example.AccountingService

El contenido del archivo es el nombre completo de la implementación:

example.impl.DefaultAccountingService

Dado que ambos archivos están en el classpath del programa, que consume el AccountingService , se puede obtener una instancia del Servicio utilizando el ServiceLauncher

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

Como el ServiceLoader es un Iterable , admite múltiples proveedores de implementación, desde donde el programa puede elegir:

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

Tenga en cuenta que al invocar next() creará una nueva instancia. Si desea reutilizar una instancia, debe utilizar el método iterator iterator() del ServiceLoader o el bucle for-each como se muestra arriba.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow