Как использовать @Autowired для решения циклических зависимостей
Что проверяют
Понимаете ли вы, как Spring создаёт бины и почему одни циклы он разрешает, а другие нет. Сильный ответ сводится к тому, что @Autowired цикл не лечит, а прячет. Следом почти всегда спрашивают, что вы сделаете с таким циклом в реальном коде.
Как отвечать
Сначала механика. Цикл через конструкторы Spring разрешить не может в принципе: чтобы создать ServiceA, нужен готовый ServiceB, и наоборот, контейнер падает с BeanCurrentlyInCreationException. Цикл через поля или сеттеры между синглтонами технически решаем: контейнер создаёт объект, кладёт раннюю ссылку в кеш синглтонов (так называемый трёхуровневый кеш) и внедряет её второму бину до окончания инициализации первого.
Важная оговорка: начиная со Spring Boot 2.6 циклические ссылки запрещены по умолчанию, и даже полевой цикл падает на старте. Вернуть старое поведение можно свойством spring.main.allow-circular-references=true, но это признание проблемы, а не решение.
Если разорвать цикл нужно прямо сейчас:
@Lazyна параметре конструктора: вместо бина внедряется прокси, настоящий объект достаётся при первом вызове метода;ObjectProvider<T>: зависимость запрашивается черезgetObject()в момент использования, а не при создании;- сеттерная инъекция: работает только при разрешённых циклах и только для синглтонов, у бинов со скоупом
prototypeцикл не разрешается никогда.
Правильный ответ архитектурный: вынести общую логику в третий сервис, от которого зависят оба, или развернуть одну из связей через события ApplicationEventPublisher. Цикл почти всегда означает, что у двух классов размыты обязанности.
Где спотыкаются
Называют @Autowired на поле решением. Оно не убирает цикл, а прячет его, и в Boot 2.6 и новее без флага приложение всё равно не стартует.
Не знают про прокси. Цикл с бином, который оборачивается в прокси, например из-за @Async, падает с ошибкой о том, что в другой бин внедрена сырая версия объекта.
Путают конструкторную и сеттерную инъекцию, как в популярных шпаргалках, где сеттеры выдают за «конструкторный способ».