Поиск…


замечания

ServiceLoader может использоваться для получения экземпляров классов, расширяющих данный тип (= служба), которые указаны в файле, упакованном в файл .jar . Сервис, который расширен / реализован, часто является интерфейсом, но это не требуется.

Расширяющиеся / реализующие классы должны предоставить конструктор нулевого аргумента для ServiceLoader для их создания.

Чтобы быть обнаруженным ServiceLoader текстовый файл с именем полного имени типа внедренной службы должен храниться внутри каталога META-INF/services в файле jar. Этот файл содержит одно полное имя класса, реализующего службу на строку.

Служба регистрации

В следующем примере показано, как создать экземпляр класса для ведения журнала через ServiceLoader .

обслуживание

package servicetest;

import java.io.IOException;

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

Реализация услуги

Следующая реализация просто записывает сообщение в 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() {
    }

}

Следующая реализация записывает сообщения в текстовый файл:

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 / услуги / servicetest.Logger

В файле META-INF/services/servicetest.Logger перечислены имена реализации Logger .

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

использование

Следующий main метод записывает сообщение всем доступным регистраторам. Регистраторы создаются с использованием 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);
        }
    }
}

Простой пример ServiceLoader

ServiceLoader - простой и простой в использовании встроенный механизм динамической загрузки реализаций интерфейса. С помощью сервис-загрузчика - обеспечения средств для создания (но не для проводки) - в Java SE может быть встроен простой механизм впрыска зависимостей. Интерфейс ServiceLoader и разделение реализации становятся естественными, и программы могут быть удобно расширены. На самом деле многие Java API внедрены на основе ServiceLoader

Основные понятия

  • Работа на интерфейсах услуг
  • Получение реализации (-ов) службы через ServiceLoader
  • Обеспечение внедрения сервисов

Давайте начнем с интерфейса и поместим его в банку, названную, например, accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

Теперь мы предоставляем реализацию этой службы в банке с именем accounting-impl.jar , содержащей реализацию услуги

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

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

  private long balanceFromDB(){
    ...
  }
}

далее, accounting-impl.jar содержит файл, объявляющий, что эта банка обеспечивает реализацию AccountingService . Файл должен иметь путь, начинающийся с META-INF/services/ и должен иметь то же имя, что и полное имя интерфейса:

  • META-INF/services/example.AccountingService

Содержимое файла является полностью qualfified имя реализации:

example.impl.DefaultAccountingService

Поскольку обе банки находятся в пути к классам программы, которая потребляет AccountingService , экземпляр службы может быть получен с помощью ServiceLauncher

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

Поскольку ServiceLoader является Iterable , он поддерживает несколько поставщиков реализации, в которых программа может выбирать:

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

Обратите внимание, что при вызове next() создан новый экземпляр. Если вы хотите повторно использовать экземпляр, вы должны использовать метод iterator() для ServiceLoader или для каждого цикла, как показано выше.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow