Jak rozwiązać problem z circural dependency

0

Witam wszystkich, pracując nad projektem w Springu, mam problem związany z circural dependency pomiędzy implementacją serwisu UserService, a implementacją serwisu RentalService.

Nie do końca mam pomysł na rozwiązanie problemu
Błąd taki jak w tym wątku (oczywiście poza klasami) - Circural dependency - jaka jest przyczyna?

Linki do kodu:
https://github.com/Mr-Victor16/car-rental-system-spring/blob/main/src%2Fmain%2Fjava%2Fcom%2Fexample%2Fcarrentalsystem%2Fservices%2FUserServiceImpl.java

https://github.com/Mr-Victor16/car-rental-system-spring/blob/main/src%2Fmain%2Fjava%2Fcom%2Fexample%2Fcarrentalsystem%2Fservices%2FRentalServiceImpl.java

1
  1. Rób mniejsze serwisy
  2. Wstrzyknij RentalRepository do UserServiceImpl i po problemie

Z innych rzeczy co na szybko wyłapałem:
3. Nie twórz interfejsów dla serwisów, jest to bez sensu, a gdy patrzę że w swoim kodzie wstrzykujesz klasy *Impl to tworzenie interfejsów jest jeszcze bardziej bez sensu.
4. Nie nazywaj beanów @Service("userService") - w sensownym kodzie nigdy nie powinieneś bazować na nazwach beanów.
5. //Role: False - USER, True - ADMIN - zrób ludziego enuma zamiast polegać na booleanie tłumaczonym za pomocą komentarza w kodzie

0

A czy wstrzyknięcie RentalRepository do UserServiceImpl nie będzie pewnego rodzaju błędem?

Wychodzę z założenia, że wszystkie operacje związane z operowaniem na RentalRepository powinny być realizowane w serwisie RentalServiceImpl

1

Zrobiłeś architekturę (chyba) warstwową, która moim zdaniem praktycznie zawsze jest błędem sama w sobie. Aczkolwiek jest w miarę przystępna do nauki i widziałem komercyjny kod tak napisany. Architektura warstwowa ma generalnie taką zasadę: wyższa warstwa zawsze wywołuje niższą. Warstwy nie wywołują wyższych i równorzędnych warstw.

Dlatego Kontroler -> Serwis -> Repo jest poprawne, a Kontroler -> Serwis -> Serwis -> Repo już niekoniecznie, bo dwie równorzędne warstwy się komunikują. W skrajnych przypadkach generuje to jakieś absurdalnie duże łańcuchy wywołań Kontroler -> Serwis -> Serwis -> ... -> Serwis -> Serwis -> Repo. Widziałem taki kod, nie polecam.

Wychodzę z założenia, że wszystkie operacje związane z operowaniem na RentalRepository powinny być realizowane w serwisie RentalServiceImpl

Przy architekturze heksagonalnej (zakładając że RentalServiceImpl jest wejściem do modułu aplikacji) tak. W architekturze warstwowej nie.

0

Patrząc po kodzie to chcesz przy usuwaniu usera usunąć też wszystkie jego rentals. Widzę 2 sposoby na to:
1.Zrób relacje one to many między userem a rental i ustaw "orphanremoval" na true. Wtedy wystarczy użyć metoda delete z UserRepository.
2.Po usunięciu usera opublikuj event typu "UserRemoved" i obsłuż go w jakimś handlerze po prostu usuwająć rentals po user id.

1

Taj jak tutaj już napisano - w tym przypadku UserServiceImpl nie powinien komunikować się z RentalServiceImpl, tylko z repozytoriami. Ba, nawet w RentalService stworzyłbym oddzielną metodę w tym celu typu, typu deleteRentals(Long userId) (bo powinno się przecież dać to ogarnąć skończoną liczbą SQLi), zamiast usuwać je pojedynczo.

Wychodzę z założenia, że wszystkie operacje związane z operowaniem na RentalRepository powinny być realizowane w serwisie RentalServiceImpl

Takie podejście tylko na tutorialach. Serwisy powinny ogarniać operacje biznesowe, jeśli operacja usunięcia użytkownika wymaga dostępu do N repozytoriów to wstrzykujesz N repozytoriów. Inaczej masz problem.

0

imo wrzuć tam kaskadę on delete i wywal to dependency z UserService. Poczytaj o CQRS, fajne rozwiązanie.

Nigdzie w moich serwisach nie jest użyte niezwiązane repo i da się, ale trzeba to dobrze przemyśleć - odpowiednia hierarchia jest kluczem.
No i jak wspomnieli poprzednicy - po co Ci interfejs? Jesli planujesz dodać inne implementacje wybierane za pomocą property, czy kontekstu, czy jakieś mocki serwisu do testów to spoko

1 użytkowników online, w tym zalogowanych: 0, gości: 1