0Pricing
Java Academy · Урок

Сервисы с provides/uses

Разделяйте компоненты с загрузчиком сервисов

«Сервисы с provides/uses» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

Развязка компонентов с помощью служб

Модули могут взаимодействовать без зависимости от реализаций друг друга, используя шаблон загрузчика служб.

Один модуль объявляет, что он uses интерфейс службы, а другой объявляет реализацию с помощью provides. JVM связывает их между собой.

Три роли

В службе участвуют три стороны:

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

Интерфейс службы

Сначала определите контракт. Это обычный интерфейс в экспортируемом пакете, поэтому на него могут ссылаться и поставщики, и потребители.

package com.example.spi;

public interface Codec {
    String name();
    byte[] encode(String input);
}

Потребитель объявляет использование

Модуль-потребитель объявляет, что он uses интерфейс. Это сообщает JPMS, что модуль будет искать реализации через ServiceLoader.

module com.example.app {
    requires com.example.spi;
    uses com.example.spi.Codec;
}

Поставщик объявляет реализацию

Модуль-поставщик объявляет, какой интерфейс он реализует, с помощью записи provides ... with ..., указывая имя своего конкретного класса.

module com.example.base64 {
    requires com.example.spi;
    provides com.example.spi.Codec
        with com.example.base64.Base64Codec;
}

Реализация поставщика

Класс реализации — это обычный Java-класс. Он должен быть общедоступным и иметь либо общедоступный конструктор без аргументов, либо общедоступный статический метод provider().

package com.example.base64;

import com.example.spi.Codec;
import java.util.Base64;

public class Base64Codec implements Codec {
    public String name() { return "base64"; }
    public byte[] encode(String input) {
        return Base64.getEncoder().encode(input.getBytes());
    }
}

Загрузка с помощью ServiceLoader

Во время выполнения потребитель запрашивает у ServiceLoader.load(Codec.class) всех доступных поставщиков и перебирает их, не имея связи на этапе компиляции ни с одной реализацией.

import com.example.spi.Codec;
import java.util.ServiceLoader;

public class App {
    public static void main(String[] args) {
        ServiceLoader<Codec> loader = ServiceLoader.load(Codec.class);
        for (Codec codec : loader) {
            System.out.println("Found codec: " + codec.name());
        }
    }
}

Почему это мощный подход

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

Это позволяет создавать архитектуры подключаемых компонентов и выполнять чистую инверсию зависимостей.

Фабрика поставщика

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

package com.example.base64;

import com.example.spi.Codec;

public class CodecFactory {
    public static Codec provider() {
        return new Base64Codec();
    }
}

Несколько поставщиков

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

Добавляйте и удаляйте поставщиков, не изменяя код потребителя.

Поток поставщиков

Начиная с Java 9, ServiceLoader предлагает stream(), возвращая дескрипторы Provider, которые можно отфильтровать до создания экземпляров. Это полезно, когда создание экземпляра требует много ресурсов.

import com.example.spi.Codec;
import java.util.ServiceLoader;

public class App {
    public static void main(String[] args) {
        Codec chosen = ServiceLoader.load(Codec.class).stream()
            .map(ServiceLoader.Provider::get)
            .filter(c -> c.name().equals("base64"))
            .findFirst()
            .orElseThrow();
        System.out.println("Using: " + chosen.name());
    }
}

Быстрая проверка

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

Итоги

Вы изучили шаблон службы модулей:

  • Три роли: интерфейс службы, поставщик, потребитель
  • Потребитель: uses; поставщик: provides ... with
  • Реализации загружаются во время выполнения через ServiceLoader
  • Поставщикам нужен общедоступный конструктор без аргументов или статический provider()

Далее: перенос существующего проекта на модули.

Часто задаваемые вопросы

Урок «Сервисы с provides/uses» бесплатный?

Да — полный текст урока «Сервисы с provides/uses» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «Сервисы с provides/uses»?

Разделяйте компоненты с загрузчиком сервисов Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Сервисы с provides/uses»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. module-info.java
  2. requires и exports
  3. Сервисы с provides/uses
  4. Переход на модули
← Назад к Java Academy