Spec-Zone.ru › OpenJDK 17

Класс ServiceLoader<S>

java.lang.Object
java.util.ServiceLoader<S>
Type Parameters:
S - Тип службы, которая должна быть загружена этим загрузчиком
Все реализуемые интерфейсы:
Iterable<S>
public final class ServiceLoader<S> extends Object implements Iterable<S>
Утилита для загрузки реализаций службы.

Служба — это известный интерфейс или класс, для которого существуют ноль, одна или несколько служб-поставщиков. Служба-поставщик (или просто поставщик) — это класс, реализующий или наследующий известный интерфейс или класс. Загрузчик служб — это объект, который находит и загружает службы-поставщики, развернутые в среде выполнения в момент, выбранный приложением. Код приложения ссылается только на службу, а не на службы-поставщики, и предполагается, что он способен выбирать между несколькими службами-поставщиками (на основе функций, которые они предоставляют через службу) и обрабатывать возможность того, что службы-поставщики не найдены.

Получение загрузчика служб

Приложение получает загрузчик служб для данной службы, вызвав один из статических методов load класса ServiceLoader. Если приложение является модулем, то его декларация модуля должна содержать директиву uses, которая указывает службу; это помогает найти поставщиков и гарантирует их надёжную работу. Кроме того, если модуль приложения не содержит службу, то его декларация модуля должна содержать директиву requires, которая указывает модуль, экспортирующий службу. Сильно рекомендуется, чтобы модуль приложения не требовал модулей, содержащих поставщиков службы.

Загрузчик служб может быть использован для поиска и создания экземпляров поставщиков службы с помощью метода iterator. ServiceLoader также определяет метод stream для получения потока поставщиков, который можно просмотреть и отфильтровать без создания экземпляров.

Например, предположим, что служба — это com.example.CodecFactory, интерфейс, который определяет методы для создания кодеров и декодеров:


     package com.example;
     public interface CodecFactory {
         Encoder getEncoder(String encodingName);
         Decoder getDecoder(String encodingName);
     }
 

Следующий код получает загрузчик служб для службы CodecFactory, а затем использует его итератор (созданный автоматически усовершенствованным циклом for) для вывода экземпляров служб-поставщиков, которые находятся:


     ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
     for (CodecFactory factory : loader) {
         Encoder enc = factory.getEncoder("PNG");
         if (enc != null)
             ... use enc to encode a PNG file
             break;
         }
 

Если этот код находится в модуле, то для ссылки на интерфейс com.example.CodecFactory модуль должен потребовать модуль, который экспортирует этот интерфейс. Декларация модуля также должна указывать использование com.example.CodecFactory:


     requires com.example.codec.core;
     uses com.example.CodecFactory;
 

Иногда приложение может захотеть просмотреть службу-поставщика перед созданием экземпляра, чтобы определить, будет ли экземпляр этой службы-поставщика полезным. Например, служба-поставщик для CodecFactory которая способна создавать кодер "PNG", может быть аннотирована с помощью @PNG. Следующий код использует метод stream загрузчика служб для вывода экземпляров Provider<CodecFactory> в отличие от того, как итератор выводит экземпляры CodecFactory:


     ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
     Set<CodecFactory> pngFactories = loader
            .stream()                                              // Note a below
            .filter(p -> p.type().isAnnotationPresent(PNG.class))  // Note b
            .map(Provider::get)                                    // Note c
            .collect(Collectors.toSet());
 
  1. Поток объектов Provider<CodecFactory>
  2. p.type() возвращает Class<CodecFactory>
  3. get() возвращает экземпляр CodecFactory

Разработка служб

Служба — это единственный тип, обычно интерфейс или абстрактный класс. Может быть использован конкретный класс, но это не рекомендуется. Тип может иметь любую доступность. Методы службы сильно зависят от области, поэтому это спецификация API не может дать конкретные рекомендации по их форме или функции. Однако есть два общих руководства:

  1. Служба должна объявлять столько методов, сколько необходимо, чтобы службы-поставщики могли сообщать о своих свойствах в конкретной области и других факторах качества реализации. Приложение, которое получает загрузчик служб для службы, может затем вызывать эти методы для каждого экземпляра службы-поставщика, чтобы выбрать лучшего поставщика для приложения.

  2. Служба должна указывать, предназначены ли её службы-поставщики для прямой реализации службы или для механизма косвенности, такого как "прокси" или "фабрика". Службы-поставщики часто являются механизмами косвенности, когда объекты в конкретной области относительно дорого создавать; в этом случае служба должна быть разработана таким образом, чтобы службы-поставщики были абстракциями, создающими "реальную" реализацию по требованию. Например, служба CodecFactory выражает через своё имя, что её службы-поставщики являются фабриками для кодеков, а не кодеками сами по себе, потому что создание определённых кодеков может быть дорогим или сложным.

Разработка служб-поставщиков

Служба-поставщик — это единственный тип, обычно конкретный класс. Разрешается интерфейс или абстрактный класс, так как он может объявлять статический метод поставщика, который обсуждается позже. Тип должен быть публичным и не должен быть вложенным классом.

Служба-поставщик и её вспомогательный код могут быть разработаны в модуле, который затем развертывается на пути модуля приложения или в модульной образе. В качестве альтернативы, служба-поставщик и её вспомогательный код могут быть упакованы в файл JAR и развернуты на пути класса приложения. Преимущество разработки службы-поставщика в модуле заключается в том, что поставщик может быть полностью инкапсулирован, чтобы скрыть все детали его реализации.

Приложение, которое получает загрузчик служб для данной службы, не обращает внимания на то, развернуты ли поставщики службы в модулях или упакованы в файлы JAR. Приложение создаёт экземпляры служб-поставщиков с помощью итератора загрузчика служб или объектов Provider в потоке загрузчика служб без знания местоположения служб-поставщиков.

Развёртывание служб-поставщиков как модулей

Служба-поставщик, разработанная в модуле, должна быть указана в директиве provides в декларации модуля. Директива provides указывает как службу, так и службу-поставщика; это помогает найти поставщика, когда другой модуль с директивой uses для службы получает загрузчик служб для этой службы. Сильно рекомендуется, чтобы модуль не экспортировал пакет, содержащий службу-поставщика. Нет поддержки для модуля, указывающего в директиве provides службу-поставщика в другом модуле.

Служба-поставщик, разработанная в модуле, не контролирует время своего создания, так как это происходит по желанию приложения, но она контролирует способ своего создания:

  • Если служба-поставщик объявляет метод поставщика, то загрузчик служб вызывает этот метод для получения экземпляра службы-поставщика. Метод поставщика — это публичный статический метод с именем "provider" без формальных параметров и типом возвращаемого значения, приводимым к интерфейсу или классу службы.

    В этом случае сама служба-поставщик не обязательно должна быть приводимой к интерфейсу или классу службы.

  • Если служба-поставщик не объявляет метод поставщика, то служба-поставщик создаётся напрямую через её конструктор поставщика. Конструктор поставщика — это публичный конструктор без формальных параметров.

    В этом случае служба-поставщик должна быть приводимой к интерфейсу или классу службы.

Служба-поставщик, развернутая как автоматический модуль на пути модуля приложения, должна иметь конструктор поставщика. Нет поддержки для метода поставщика в этом случае.

Например, предположим, что модуль указывает следующую директиву:


     provides com.example.CodecFactory with com.example.impl.StandardCodecs,
              com.example.impl.ExtendedCodecsFactory;
 

где

  • com.example.CodecFactory — это служба из двух методов, упомянутая ранее.
  • com.example.impl.StandardCodecs — это публичный класс, реализующий CodecFactory и имеющий публичный конструктор без аргументов.
  • com.example.impl.ExtendedCodecsFactory — это публичный класс, не реализующий CodecFactory, но он объявляет публичный статический метод без аргументов с именем "provider" и типом возвращаемого значения CodecFactory.

Загрузчик служб создаст экземпляр StandardCodecs через его конструктор и создаст экземпляр ExtendedCodecsFactory, вызвав его метод provider. Требование о том, что конструктор поставщика или метод поставщика является публичным, помогает документировать намерение о том, что класс (то есть служба-поставщик) будет создан сущностью (то есть загрузчиком служб), которая находится вне пакета класса.

Развёртывание служб-поставщиков на пути класса

Служба-поставщик, упакованная в файл JAR для пути класса, определяется путём размещения файла конфигурации поставщика в каталоге ресурсов META-INF/services. Имя файла конфигурации поставщика — полностью квалифицированное двоичное имя службы. Файл конфигурации поставщика содержит список полностью квалифицированных двоичных имён служб-поставщиков, по одному на строке.

Например, предположим, что служба-поставщик com.example.impl.StandardCodecs упакована в файл JAR для пути класса. Файл JAR будет содержать файл конфигурации поставщика с именем:

META-INF/services/com.example.CodecFactory
содержащий строку:
com.example.impl.StandardCodecs # Standard codecs

Файл конфигурации поставщика должен быть закодирован в UTF-8. Пробелы и символы табуляции вокруг имени каждой службы-поставщика, а также пустые строки игнорируются. Символ комментария — '#' (U+0023 ДИЕЗ); на каждой строке все символы после первого символа комментария игнорируются. Если имя класса службы-поставщика указано в файле конфигурации поставщика более одного раза, дубликат игнорируется. Если класс службы-поставщика указан в нескольких файлах конфигурации, дубликат игнорируется.

Служба-поставщик, упомянутая в файле конфигурации поставщика, может находиться в том же файле JAR, что и файл конфигурации поставщика, или в другом файле JAR. Служба-поставщик должна быть видна из загрузчика классов, который первоначально запрашивается для поиска файла конфигурации поставщика; это не обязательно тот загрузчик классов, который в конечном итоге найдёт файл конфигурации поставщика.

Время обнаружения поставщиков

Службы-поставщики загружаются и создаются лениво, то есть по требованию. Загрузчик служб сохраняет кэш загруженных поставщиков. Каждый вызов метода iterator возвращает итератор, который сначала возвращает все элементы, кэшированные из предыдущей итерации, в порядке создания экземпляров, а затем лениво находит и создаёт все оставшиеся поставщики, добавляя каждый из них в кэш по очереди. Аналогично, каждый вызов метода stream возвращает поток, который сначала обрабатывает все поставщики, загруженные предыдущими операциями потока, в порядке загрузки, а затем лениво находит все оставшиеся поставщики. Кэши очищаются с помощью метода reload.

Ошибки

При использовании загрузчика сервисов iterator, методы hasNext и next завершатся с ошибкой ServiceConfigurationError, если произошла ошибка при поиске, загрузке или создании поставщика сервиса. При обработке потока загрузчика сервисов, ServiceConfigurationError может быть выброшено любым методом, вызывающим поиск или загрузку поставщика сервиса.

При загрузке или создании поставщика сервиса в модуле, ServiceConfigurationError может быть выброшено по следующим причинам:

  • Поставщик сервиса не может быть загружен.
  • Поставщик сервиса не объявляет метод поставщика, и он не может быть приведён к интерфейсу/классу сервиса или не имеет конструктора поставщика.
  • Поставщик сервиса объявляет публичный статический метод без аргументов с именем "provider" и типом возвращаемого значения, который не может быть приведён к интерфейсу или классу сервиса.
  • Файл класса поставщика сервиса содержит более одного публичного статического метода без аргументов с именем "provider".
  • Поставщик сервиса объявляет метод поставщика, и он завершается, возвращая null или выбрасывая исключение.
  • Поставщик сервиса не объявляет метод поставщика, и его конструктор поставщика завершается с ошибкой, выбросив исключение.

При чтении файла конфигурации поставщика или загрузке или создании класса поставщика, указанного в файле конфигурации поставщика, ServiceConfigurationError может быть выброшено по следующим причинам:

  • Формат файла конфигурации поставщика нарушает формат, указанный выше;
  • Происходит ошибка IOException при чтении файла конфигурации поставщика;
  • Поставщик сервиса не может быть загружен;
  • Поставщик сервиса не может быть приведён к интерфейсу или классу сервиса, или не определяет конструктор поставщика, или не может быть создан.

Безопасность

Загрузчики сервисов всегда выполняются в контексте безопасности вызывающего метода итератора или потока, а также могут быть ограничены контекстом безопасности вызвавшего загрузчик сервиса. Доверенный системный код обычно должен вызывать методы в этом классе и методы возвращаемых итераторов из привилегированного контекста безопасности.

Конкурентность

Экземпляры этого класса не предназначены для одновременного использования несколькими потоками.

Обработка нулевых значений

Если не указано иное, передача null аргумента любому методу в этом классе приведет к выбросу NullPointerException.

С момента:
1.6

Краткое описание вложенных классов

Модификатор и тип Класс Описание
static interface  ServiceLoader.Provider<S>
Представляет поставщика сервиса, найденного ServiceLoader.

Краткое описание методов

Модификатор и тип Метод Описание
Optional<S> findFirst()
Загружает первый доступный поставщик сервиса для данного загрузчика.
Iterator<S> iterator()
Возвращает итератор для ленивой загрузки и создания доступных поставщиков сервиса для данного загрузчика.
static <S> ServiceLoader<S> load(Class<S> service)
Создаёт новый загрузчик сервисов для заданного типа сервиса, используя контекстный загрузчик класса текущего потока.
static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
Создаёт новый загрузчик сервисов для заданного сервиса.
static <S> ServiceLoader<S> load(ModuleLayer layer, Class<S> service)
Создаёт новый загрузчик сервисов для заданного типа сервиса для загрузки поставщиков сервиса из модулей в заданном уровне модулей и его предков.
static <S> ServiceLoader<S> loadInstalled(Class<S> service)
Создаёт новый загрузчик сервисов для заданного типа сервиса, используя платформенный загрузчик классов.
void reload()
Очищает кэш поставщиков данного загрузчика, чтобы все поставщики были загружены заново.
Stream<ServiceLoader.Provider<S>> stream()
Возвращает поток для ленивой загрузки доступных поставщиков сервиса для данного загрузчика.
String toString()
Возвращает строку, описывающую этот сервис.

Методы, унаследованные от класса java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Методы, унаследованные от интерфейса java.lang.Iterable

forEach, spliterator

Подробное описание методов

iterator

public Iterator<S> iterator()
Возвращает итератор для ленивой загрузки и создания доступных поставщиков сервиса этого загрузчика.

Для достижения ленивой загрузки фактическая работа по поиску и созданию поставщиков выполняется самим итератором. Его методы hasNext и next могут, следовательно, выбросить исключение ServiceConfigurationError по любой из причин, указанных в разделе Ошибки выше. Для написания надёжного кода необходимо только перехватывать ServiceConfigurationError при использовании итератора. Если ошибка возникает, то последующие вызовы итератора будут делать всё возможное, чтобы найти и создать следующего доступного поставщика, но в общем случае такая регенерация не гарантируется.

Кэширование: Возвращаемый этим методом итератор сначала возвращает все элементы кэша поставщиков в том порядке, в котором они были загружены. Затем он лениво загружает и создаёт любые оставшиеся поставщики сервиса, добавляя каждый из них в кэш по очереди. Если кэши поставщиков этого загрузчика очищаются путём вызова метода reload, то существующие итераторы для этого загрузчика сервиса должны быть удалены. Методы hasNext и next итератора выбросят исключение ConcurrentModificationException, если они будут использованы после очистки кэша поставщиков.

Итератор, возвращаемый этим методом, не поддерживает удаление. Вызов его метода remove вызовет исключение UnsupportedOperationException.

Указано в:
iterator в интерфейсе Iterable<S>
Примечание API:
Выбрасывание ошибки в этих случаях может показаться чрезмерным. Обоснование этого поведения заключается в том, что файл конфигурации поставщика с неправильным форматом, подобно файлу с неправильным форматом класса, указывает на серьёзную проблему с настройкой или использованием виртуальной машины Java. Поэтому предпочтительнее выбросить ошибку, чем пытаться восстановиться или, что ещё хуже, пропустить её безмолвно.
Возвращает:
Итератор, который лениво загружает поставщиков для сервиса этого загрузчика

stream

public Stream<ServiceLoader.Provider<S>> stream()
Возвращает поток для ленивой загрузки доступных поставщиков сервиса этого загрузчика. Элементы потока имеют тип Provider, метод Provider's get должен быть вызван для получения или создания поставщика.

Для достижения ленивой загрузки фактическая работа по поиску поставщиков выполняется при обработке потока. Если поставщик сервиса не может быть загружен по какой-либо из причин, указанных в разделе Ошибки выше, то ServiceConfigurationError выбрасывается любым методом, который вызвал загрузку поставщика сервиса.

Кэширование: При обработке потока сначала обрабатываются поставщики, которые ранее были загружены операциями потока, в порядке загрузки. Затем лениво загружаются любые оставшиеся поставщики сервиса. Если кэши поставщиков этого загрузчика очищаются путём вызова метода reload, то существующие потоки для этого загрузчика сервиса должны быть удалены. Источник возвращённого потока spliterator является быстропроверяемым и выбросит исключение ConcurrentModificationException, если кэш поставщиков был очищен.

Следующие примеры демонстрируют использование. Первый пример создаёт поток объектов CodecFactory, второй пример такой же, за исключением того, что он сортирует поставщиков по имени класса поставщика (и таким образом находит всех поставщиков).


    Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.class)
            .stream()
            .map(Provider::get);

    Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.class)
            .stream()
            .sorted(Comparator.comparing(p -> p.type().getName()))
            .map(Provider::get);
 
Возвращает:
Поток, который лениво загружает поставщиков для сервиса этого загрузчика
С:
9

load

public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
Создаёт новый загрузчик сервиса для данного сервиса. Загрузчик сервиса использует заданный загрузчик классов в качестве отправной точки для поиска поставщиков сервиса для сервиса. Загрузчик сервиса с помощью iterator и stream находит поставщиков как в именованных, так и в безымянных модулях следующим образом:
  • Шаг 1: Поиск поставщиков в именованных модулях.

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

    Кроме того, если загрузчик классов не является загрузчиком базовых классов или платформенным загрузчиком классов, то поставщики сервиса могут быть найдены в именованных модулях других загрузчиков классов. В частности, если у загрузчика классов или любого загрузчика классов, доступного через делегирование родителя, есть модуль в слое модуля, то поставщики сервиса во всех модулях в слое модуля находятся.

    Пример: предположим, что есть слой модуля, где каждый модуль находится в своём загрузчике классов (см. defineModulesWithManyLoaders). Если этот метод ServiceLoader.load вызывается для поиска поставщиков, используя любой из загрузчиков классов, созданных для слоя модуля, то он будет находить всех поставщиков в слое модуля, независимо от их определяющего загрузчика классов.

    Порядок: загрузчик сервиса сначала найдёт любые поставщики сервиса в модулях, определённых для загрузчика классов, затем в родительском загрузчике классов, его родительском родителе и так далее до загрузчика базовых классов. Если у загрузчика классов есть модули в слое модуля, то все поставщики в этом слое модуля находятся (независимо от их загрузчика классов) перед поставщиками в родительском загрузчике классов. Порядок модулей в одном загрузчике классов или порядок модулей в слое модуля не определён.

    Если модуль объявляет более одного поставщика, то поставщики находятся в том порядке, в котором его модульный дескриптор перечисляет поставщиков. Поставщики, динамически добавленные агентами инструментирования (см. redefineModule) всегда находятся после поставщиков, объявленных модулем.

  • Шаг 2: Поиск поставщиков в безымянных модулях.

    Поставщики сервиса в безымянных модулях находятся, если их имена классов перечислены в файлах конфигурации поставщиков, которые находятся методом getResources загрузчика классов.

    Порядок основан на порядке, в котором метод getResources загрузчика классов находит файлы конфигурации сервисов, и в пределах этого порядка на порядке, в котором имена классов перечислены в файле.

    Любое упоминание о поставщике сервиса, развернутом в именованном модуле, игнорируется в файле конфигурации поставщика. Это сделано для того, чтобы избежать дублирования, которое могло бы возникнуть, если бы именованный модуль имел как директиву provides, так и файл конфигурации поставщиков, упоминающий того же поставщика сервиса.

    Класс поставщика должен быть виден загрузчику классов.

Примечание API:
Если путь к классу загрузчика классов включает удалённые сетевые URL-адреса, то эти URL-адреса могут быть обработаны в процессе поиска файлов конфигурации поставщиков.

Эта активность является нормальной, хотя может вызывать путаницу в логах веб-сервера. Однако, если веб-сервер не настроен должным образом, это может привести к тому, что алгоритм загрузки поставщиков будет работать некорректно.

Веб-сервер должен возвращать ответ HTTP 404 (Не найдено) при отсутствии запрошенного ресурса. Однако иногда веб-серверы по ошибке настроены на возврат ответа HTTP 200 (OK) вместе с полезной страницей ошибки HTML в таких случаях. Это приведёт к тому, что в этом классе будет выброшено исключение ServiceConfigurationError при попытке парсить страницу HTML как файл конфигурации поставщиков. Лучшим решением этой проблемы является исправление неправильно настроенного веб-сервера, чтобы он возвращал правильный код ответа (HTTP 404) вместе со страницей ошибки HTML.

Параметры типа:
S - класс типа сервиса
Параметры:
service - Интерфейс или абстрактный класс, представляющий сервис
loader - Загрузчик классов, используемый для загрузки файлов конфигурации поставщиков и классов поставщиков, или null, если нужно использовать системный загрузчик классов (или, если это невозможно, загрузчик базовых классов)
Возвращает:
Новый загрузчик сервиса
Выбрасывает:
ServiceConfigurationError - если тип сервиса недоступен для вызывающего абонента или вызывающий абонент находится в явном модуле, и его модульный дескриптор не объявляет, что он использует service

load

public static <S> ServiceLoader<S> load(Class<S> service)
Создаёт новый загрузчик сервиса для заданного типа сервиса, используя текущий контекстный загрузчик потока.

Вызов этого вспомогательного метода в формате


     ServiceLoader.load(service)
 
эквивалентен

     ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
 
Примечание API:
Объекты загрузчика сервиса, полученные с помощью этого метода, не должны кэшироваться во всём виртуальном оборудовании. Например, разные приложения в одной и той же виртуальной машине могут иметь разные контекстные загрузчики потока. Поиск одним приложением может найти поставщика сервиса, который виден только через его контекстный загрузчик потока, и поэтому он не подходит для поиска другим приложением. Также могут возникнуть утечки памяти. Для некоторых приложений может подойти локальная переменная потока.
Параметры типа:
S - класс типа сервиса
Параметры:
service - Интерфейс или абстрактный класс, представляющий сервис
Возвращает:
Новый загрузчик сервиса
Выбрасывает:
ServiceConfigurationError - если тип сервиса недоступен для вызывающего абонента или вызывающий абонент находится в явном модуле, и его модульный дескриптор не объявляет, что он использует service

loadInstalled

public static <S> ServiceLoader<S> loadInstalled(Class<S> service)
Создаёт новый загрузчик сервисов для заданного типа сервиса, используя платформенный загрузчик классов.

Этот метод-удобство эквивалентен следующему:


     ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
 

Этот метод предназначен для использования в тех случаях, когда требуется только доступ к установленным провайдерам. Результирующий загрузчик сервисов будет находить и загружать только провайдеров, которые были установлены в текущей виртуальной машине Java; провайдеры из пути модуля или класса приложения будут игнорироваться.

Type Parameters:
S - класс типа сервиса
Parameters:
service - интерфейс или абстрактный класс, представляющий сервис
Returns:
Новый загрузчик сервисов
Throws:
ServiceConfigurationError - если тип сервиса недоступен для вызывающего объекта или вызывающий объект находится в явном модуле, а его дескриптор модуля не объявляет, что он использует service

load

public static <S> ServiceLoader<S> load(ModuleLayer layer, Class<S> service)
Создаёт новый загрузчик сервисов для заданного типа сервиса, чтобы загружать провайдеров сервисов из модулей в заданном слое модулей и его предках. Он не ищет провайдеров в безымянных модулях. Порядок, в котором загрузчик сервисов iterator и stream находят провайдеров и возвращают элементы, следующий:
  • Провайдеры находятся в слое модуля перед поиском провайдеров в родительских слоях. Проход по родительским слоям происходит в глубину, и каждый слой посещается не более одного раза. Например, предположим, что L0 — это загрузочный слой, L1 и L2 — это слои модулей с L0 в качестве родительского слоя. Теперь предположим, что L3 создан с L1 и L2 в качестве родителей (в указанном порядке). Использование загрузчика сервисов для поиска провайдеров с L3 в качестве контекста найдёт провайдеров в следующем порядке: L3, L1, L0, L2.

  • Если модуль объявляет более одного провайдера, провайдеры находятся в порядке, в котором его дескриптор модуля перечисляет провайдеров. Провайдеры, добавленные динамически агентами инструментирования, всегда находятся после провайдеров, объявленных модулем.

  • Порядок модулей в слое модуля не определён.

API Note:
В отличие от других методов загрузки, определённых здесь, тип сервиса является вторым параметром. Причина этого — избежание проблем совместимости исходного кода для кода, использующего load(S, null).
Type Parameters:
S - класс типа сервиса
Parameters:
layer - слой модулей
service - интерфейс или абстрактный класс, представляющий сервис
Returns:
Новый загрузчик сервисов
Throws:
ServiceConfigurationError - если тип сервиса недоступен для вызывающего объекта или вызывающий объект находится в явном модуле, а его дескриптор модуля не объявляет, что он использует service
Since:
9

findFirst

public Optional<S> findFirst()
Загружает первого доступного провайдера сервиса данного загрузчика. Этот метод-удобство эквивалентен вызову метода iterator() и получению первого элемента. Поэтому он возвращает первый элемент из кэша провайдеров, если это возможно; в противном случае он пытается загрузить и создать первый провайдер.

Следующий пример загружает первого доступного провайдера сервиса. Если провайдеры сервиса не найдены, он использует реализацию по умолчанию.


    CodecFactory factory = ServiceLoader.load(CodecFactory.class)
                                        .findFirst()
                                        .orElse(DEFAULT_CODECSET_FACTORY);
 
Returns:
Первый провайдер сервиса или пустое Optional значение, если провайдеры сервисов не найдены
Throws:
ServiceConfigurationError - Если класс провайдера не может быть загружен по какой-либо из причин, указанных в разделе «Ошибки» выше.
Since:
9

reload

public void reload()
Очищает кэш провайдеров этого загрузчика, чтобы все провайдеры были перезагружены.

После вызова этого метода последующие вызовы методов iterator или stream будут лениво искать провайдеров (и создавать их в случае iterator) с нуля, как и в случае с вновь созданным загрузчиком сервисов.

Этот метод предназначен для ситуаций, в которых новые провайдеры сервисов могут быть установлены в работающую виртуальную машину Java.

toString

public String toString()
Возвращает строку, описывающую этот сервис.
Overrides:
toString в классе Object
Returns:
Описание в виде строки

© 1993, 2021, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ServiceLoader.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API