--- aliases: tags: - зрелость/🌱 date: - - 2023-11-20 zero-link: - "[[../../../../garden/ru/meta/zero/00 Java разработка]]" parents: linked: - "[[SpringBoot]]" article: https://note.struchkov.dev/sircular-service-dependencies/ --- Циклические зависимости между сервисами возникают, когда сервисы взаимно внедряются друг в друга. Например, сервис А внедряет сервис Б, но в тоже время сервис Б внедряет сервис А. В этом случае [Spring](https://note.struchkov.dev/tag/spring/) и [Quarkus](https://note.struchkov.dev/tag/quarkus/) не знают, как создать такие бины и внедрить их друг в друга. > [!WARNING] > Обычно такая ситуация сигнализирует о плохо продуманной архитектуре приложения.  Пример циклической зависимости в Spring: ```java @Service public class ServiceOne { private final ServiceTwo serviceTwo; public ServiceOne(ServiceTwo serviceTwo) { this.serviceTwo = serviceTwo; } } ``` ```java @Service public class ServiceTwo { private final ServiceOne serviceOne; public ServiceTwo(ServiceOne serviceOne) { this.serviceOne = serviceOne; } } ``` Вот что вы можете с этим сделать: ## Пересмотреть архитектуру приложения ==Это предпочтительный вариант.== Возможно вам стоит создать сервис В, который внедрит в себя сервисы А и Б. В таком случае вы распутаете циклическую зависимость. ```java @Service public class ServiceThree { private final ServiceOne serviceOne; private final ServiceTwo serviceTwo; public ServiceThree(ServiceOne serviceOne, ServiceTwo serviceTwo) { this.serviceOne = serviceOne; this.serviceTwo = serviceTwo; } } ``` ```java @Service public class ServiceOne { } ``` ```java @Service public class ServiceTwo { } ``` ## Ленивое внедрение В Spring вы можете указать аннотацию `@Lazy` у аргумента конструктора одного их сервисов. Таким образом сначала будет создан один сервис, для второго сервиса спринг создаст прокси класс, создаст из него бин и внедрит его в ваш сервис. После чего создаст второй сервис и внедрит туда уже созданный первый. А далее заменит ссылку с прокси объекта на второй сервис. ```java @Service public class ServiceTwo { private final ServiceOne serviceOne; public ServiceTwo(@Lazy ServiceOne serviceOne) { this.serviceOne = serviceOne; } } ``` ```java @Service public class ServiceOne { private final ServiceTwo serviceTwo; public ServiceOne(ServiceTwo serviceTwo) { this.serviceTwo = serviceTwo; } } ``` ## Внедрение через Setter Внедрить один из сервисов через сеттер, вместо конструктора. Таким образом, фреймворк сможет создать оба бина, а потом уже внедрит один в другой. ```java @Service public class ServiceOne { private final ServiceTwo serviceTwo; public ServiceOne(ServiceTwo serviceTwo) { this.serviceTwo = serviceTwo; } } ``` ```java @Service public class ServiceTwo { private ServiceOne serviceOne; @Autowired public void setServiceOne(ServiceOne serviceOne) { this.serviceOne = serviceOne; } } ```