digital-garden/knowledge/dev/java/other/Циклические зависимости сервисов.md

135 lines
3.9 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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:
- зрелость/🌱
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;
}
}
```