145 lines
4.3 KiB
Markdown
145 lines
4.3 KiB
Markdown
---
|
||
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) -->
|