digital-garden/dev/architecture/Циклические зависимости сервисов.md
Struchkov Mark 6d903d4988
Some checks failed
continuous-integration/drone/push Build is failing
Обновление
2024-11-24 20:43:38 +03:00

145 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
aliases:
tags:
- maturity/🌱
date:
- - 2023-11-20
zero-link:
- "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]"
parents:
linked:
---
Циклические зависимости между сервисами возникают, когда сервисы взаимно внедряются друг в друга. Например, сервис А внедряет сервис Б, но в тоже время сервис Б внедряет сервис А. В этом случае [SpringBoot](../../meta/zero/00%20SpringBoot.md) и [Quarkus](../../meta/zero/00%20Quarkus.md) не знают, как создать такие бины и внедрить их друг в друга.
> [!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;
}
}
```
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
**Родитель**::
**Источник**::
**Автор**::
**Создана**:: [[2023-11-20]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->