digital-garden/dev/architecture/Циклические зависимости сервисов.md
Struchkov Mark 7a7f4d17c6
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
Циклические зависимости сервисов.md
2024-09-08 12:36:52 +03:00

3.8 KiB
Raw Blame History

aliases tags date zero-link parents linked
maturity/🌱
2023-11-20
../../meta/zero/00 Архитектура ПО

Циклические зависимости между сервисами возникают, когда сервисы взаимно внедряются друг в друга. Например, сервис А внедряет сервис Б, но в тоже время сервис Б внедряет сервис А. В этом случае SpringBoot и Quarkus не знают, как создать такие бины и внедрить их друг в друга.

Warning

Обычно такая ситуация сигнализирует о плохо продуманной архитектуре приложения. 

Пример циклической зависимости в Spring:

@Service
public class ServiceOne {

    private final ServiceTwo serviceTwo;

    public ServiceOne(ServiceTwo serviceTwo) {
        this.serviceTwo = serviceTwo;
    }

}
@Service
public class ServiceTwo {

    private final ServiceOne serviceOne;

    public ServiceTwo(ServiceOne serviceOne) {
        this.serviceOne = serviceOne;
    }

}

Вот что вы можете с этим сделать:

Пересмотреть архитектуру приложения

==Это предпочтительный вариант.== Возможно вам стоит создать сервис В, который внедрит в себя сервисы А и Б. В таком случае вы распутаете циклическую зависимость.

@Service
public class ServiceThree {

    private final ServiceOne serviceOne;
    private final ServiceTwo serviceTwo;

    public ServiceThree(ServiceOne serviceOne, ServiceTwo serviceTwo) {
        this.serviceOne = serviceOne;
        this.serviceTwo = serviceTwo;
    }
    
}
@Service
public class ServiceOne {

}
@Service
public class ServiceTwo {

}

Ленивое внедрение

В Spring вы можете указать аннотацию @Lazy у аргумента конструктора одного их сервисов. Таким образом сначала будет создан один сервис, для второго сервиса спринг создаст прокси класс, создаст из него бин и внедрит его в ваш сервис. После чего создаст второй сервис и внедрит туда уже созданный первый. А далее заменит ссылку с прокси объекта на второй сервис.

@Service
public class ServiceTwo {

    private final ServiceOne serviceOne;

    public ServiceTwo(@Lazy ServiceOne serviceOne) {
        this.serviceOne = serviceOne;
    }

}
@Service
public class ServiceOne {

    private final ServiceTwo serviceTwo;

    public ServiceOne(ServiceTwo serviceTwo) {
        this.serviceTwo = serviceTwo;
    }

}

Внедрение через Setter

Внедрить один из сервисов через сеттер, вместо конструктора. Таким образом, фреймворк сможет создать оба бина, а потом уже внедрит один в другой.

@Service
public class ServiceOne {

    private final ServiceTwo serviceTwo;

    public ServiceOne(ServiceTwo serviceTwo) {
        this.serviceTwo = serviceTwo;
    }

}
@Service
public class ServiceTwo {

    private ServiceOne serviceOne;

    @Autowired
    public void setServiceOne(ServiceOne serviceOne) {
        this.serviceOne = serviceOne;
    }

}