3.9 KiB
aliases | tags | date | zero-link | parents | linked | article | |||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
|
https://note.struchkov.dev/sircular-service-dependencies/ |
Циклические зависимости между сервисами возникают, когда сервисы взаимно внедряются друг в друга. Например, сервис А внедряет сервис Б, но в тоже время сервис Б внедряет сервис А. В этом случае Spring и 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;
}
}