Как в Spring создать бин, зависящий от других бинов?

«Как в Spring создать бин, зависящий от других бинов?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Зависимости между бинами — основа Spring IoC (Inversion of Control). Spring автоматически внедряет (injects) требуемые бины через механизм DI (Dependency Injection).

Основные способы внедрения зависимости:

  1. Внедрение через конструктор (рекомендуемый способ):

    @Service
    public class OrderService {
        private final PaymentService paymentService;
        private final NotificationService notificationService;
    
        // @Autowired опционален для единственного конструктора начиная с Spring 4.3
        public OrderService(PaymentService paymentService, 
                            NotificationService notificationService) {
            this.paymentService = paymentService;
            this.notificationService = notificationService;
        }
    }
    • Плюсы: Неизменяемость (final), явные зависимости, удобство тестирования.
  2. Внедрение через поле (Field Injection):

    @Service
    public class OrderService {
        @Autowired
        private PaymentService paymentService;
    }
    • Минусы: Скрывает зависимости, усложняет тестирование (нужен Spring контекст или рефлексия), нельзя объявить поле как final.
  3. Внедрение через сеттер (Setter Injection):

    @Service
    public class OrderService {
        private PaymentService paymentService;
    
        @Autowired
        public void setPaymentService(PaymentService paymentService) {
            this.paymentService = paymentService;
        }
    }
    • Применение: Для опциональных зависимостей или когда нужна возможность переконфигурации бина после его создания.

Аннотации для внедрения:

  • @Autowired (Spring-specific) — разрешает зависимость по типу.
  • @Inject (стандарт JSR-330) — аналог @Autowired.
  • @Resource (стандарт JSR-250) — разрешает сначала по имени, затем по типу.

Условие: Зависимый бин (например, PaymentService) также должен быть управляемым Spring (помечен @Component, @Service и т.д.) и находиться в том же или доступном контексте.