135 lines
3.9 KiB
Markdown
135 lines
3.9 KiB
Markdown
|
---
|
|||
|
aliases:
|
|||
|
tags:
|
|||
|
- зрелость/🌱
|
|||
|
date:
|
|||
|
- - 2023-11-20
|
|||
|
zero-link:
|
|||
|
- "[[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;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|