Что такое циклическая зависимость бинов в Spring и как её решить?

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

Ответ

Циклическая зависимость возникает, когда два или более бина Spring зависят друг от друга, образуя замкнутый круг (например, ABA). Контейнер Spring обнаружит это во время создания контекста и выбросит BeanCurrentlyInCreationException.

Основные способы решения:

  1. Использование @Lazy — откладывает инициализацию одного из бинов до момента его первого использования, разрывая цикл на этапе создания контекста.

    @Service
    public class ServiceA {
        private final ServiceB serviceB;
    
        public ServiceA(@Lazy ServiceB serviceB) {
            this.serviceB = serviceB;
        }
    }
  2. Рефакторинг архитектуры — лучший подход. Общую логику можно вынести в третий, независимый компонент, или использовать паттерн «инверсия зависимостей» через интерфейсы.

  3. Использование сеттера или поля (Field Injection) — Spring может разрешить цикл, если инъекция происходит через сеттер или прямо в поле, а не через конструктор. Это считается антипаттерном, так как скрывает зависимости и усложняет тестирование.

    @Service
    public class ServiceA {
        @Autowired
        private ServiceB serviceB;
    }

Рекомендация: Циклические зависимости — признак проблем с проектированием модулей. Следует стремиться избегать их через правильное разделение ответственности.