Получить доступ

Как внедрить сразу все реализации интерфейса и выбирать нужную в рантайме?

MiddleIoC и внедрение зависимостейSpring
Ещё спрашивают так:
  • Как реализовать паттерн «стратегия» на Spring?
Коротко

Внедрить **List<T> или Map<String, T>**: Spring передаст все бины типа. Список — в порядке @Order, карта — с именами бинов в ключах. Нужная стратегия выбирается в рантайме.

  • Новая реализация — просто новый бин, код выбора не меняется
  • Лучше ключ из самой стратегии (type()), чем имя бина
  • Нет ни одной реализации — пустой список не падает только с ObjectProvider или List + required=false

А ещё ObjectProvider<T> — ленивый доступ и stream() по всем бинам

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Задача: платежи разных типов (карта, СБП, баланс) обрабатываются разными реализациями PaymentGateway; выбор — по типу платежа в запросе.

Решение:

public interface PaymentGateway {
    PaymentType type();
    Receipt pay(Payment p);
}

@Service
class PaymentService {
    private final Map<PaymentType, PaymentGateway> byType;
    PaymentService(List<PaymentGateway> gateways) {
        this.byType = gateways.stream()
            .collect(Collectors.toMap(PaymentGateway::type, g -> g));   // упадёт при дубле типа — и хорошо
    }
    Receipt pay(Payment p) {
        var g = byType.get(p.type());
        if (g == null) throw new UnsupportedPaymentException(p.type());
        return g.pay(p);
    }
}

Варианты внедрения:

  • List<PaymentGateway> — все бины, порядок по @Order/Ordered;
  • Map<String, PaymentGateway> — ключ — имя бина (хрупко при переименовании, поэтому лучше строить свою карту по ключу из стратегии);
  • ObjectProvider<PaymentGateway> — orderedStream(), getIfAvailable(), ленивое получение.

Плюсы: открыто для расширения — новая стратегия добавляется новым бином; нет if/else по типам; каждая стратегия тестируется отдельно.

Что хотят услышать

  • Внедрение List и Map всех реализаций.
  • Выбор стратегии по ключу в рантайме.
  • @Order и ObjectProvider — плюс.

Частые ошибки

  • Ключ по имени бина, который ломается при переименовании класса.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Внедрить List<PaymentGateway> или Map<String, PaymentGateway> — Spring передаст все бины этого типа; выбирать по ключу или методу supports()
  • ✗Это невозможно — нужно внедрять каждую реализацию отдельным полем
  • ✗Через ApplicationContext.getBean в каждом вызове
  • ✗Пометить все реализации @Primary

Что спросят дальше

  • Чем @Primary отличается от @Qualifier?
  • Что будет при двух @Primary?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем