Gdzie należy przechowywać adnotację @Service? Interfejs czy implementacja?

133

Tworzę aplikację przy użyciu Springa. Muszę użyć @Serviceadnotacji. Mam ServiceIi ServiceImpltakie to ServiceImpl implements ServiceI. Nie wiem, gdzie mam zachować @Serviceadnotację.

Czy powinienem oznaczyć interfejs lub implementację za pomocą @Service? Jakie są różnice między tymi dwoma podejściami?

TheKojuEffect
źródło
To jest moja odpowiedź na podobny post: stackoverflow.com/questions/38618995/ ...
Agustí Sánchez

Odpowiedzi:

140

Nigdy nie umieszczałem @Component(ani @Service...) na interfejsie, ponieważ czyni go to bezużytecznym. Pozwól mi wyjaśnić, dlaczego.

zastrzeżenie 1: Jeśli masz interfejs, chcesz użyć tego interfejsu dla typu punktu wtrysku.

Twierdzenie 2: Celem interfejsu jest zdefiniowanie kontraktu, który może zostać zaimplementowany przez kilka implementacji. Po drugiej stronie masz swój punkt wstrzyknięcia ( @Autowired). Posiadanie tylko jednego interfejsu i tylko jednej klasy, która go implementuje, jest (IMHO) bezużyteczne i narusza YAGNI .

Fakt: Kiedy umieścisz:

  • @Component(lub @Service...) na interfejsie,
  • mieć wiele klas, które to implementują,
  • co najmniej dwie klasy stają się wiosennymi fasolkami i
  • mieć punkt wtrysku, który wykorzystuje interfejs do wtrysku opartego na typie,

wtedy otrzymasz i NoUniqueBeanDefinitionException (lub masz bardzo specjalną konfigurację, ze środowiskiem, profilami lub kwalifikatorami ...)

Wniosek: jeśli używasz @Component(lub @Service, ...) na interfejsie, musisz naruszyć co najmniej jedną z dwóch klauzul. Dlatego myślę, że nie jest użyteczne (z wyjątkiem niektórych rzadkich scenariuszy) umieszczanie @Componentna poziomie interfejsu.


Interfejsy Spring-Data-JPA Repository to coś zupełnie innego

Ralph
źródło
3
To bardzo interesujące, co piszesz ... więc który sposób jest właściwy? Czy w ogóle nie dodaje adnotacji do interfejsu i nie nadaje adnotacji usługi do implementacji? Czy Spring nadal może automatycznie okablować przy użyciu typu interfejsu? Jaka jest twoja odpowiedź na to> stackoverflow.com/questions/12899372/ ...
corlaez
3
Mam pytanie, dlaczego musimy tworzyć interfejs dla warstwy usług, skoro jest tylko jedna klasa, która ją implementuje? Widziałem wiele projektów, mają warstwę kontrolera, ** warstwę usługową ( servicInterface , serviceInterfaceImpl ) i warstwę repozytorium .
Yubaraj
4
@Yubaraj: słuszna uwaga, ale twoje pytanie dotyczy zupełnie innego tematu (do mojej odpowiedzi przyjąłem założenie: że jest interfejs i nie chodzi o posiadanie interfejsu, ale o to, gdzie umieścić adnotację). Na twoje pytanie: nie ma prawie żadnego powodu, aby mieć interfejs dla klasy usług biznesowych, który nigdy nie będzie miał dwóch implementacji. (BTW: tak długo, jak nie budujesz interfejsu API dla kogoś innego, zawsze możesz zmienić kod i wprowadzić interfejs później, kiedy go potrzebujesz)
Ralph
1
@Yubaraj, interfejsy pozwalają na tworzenie lekkich serwerów proxy jdk opartych na interfejsach dla fasoli, gdy jest to potrzebne. Gdy nie ma interfejsu, spring musi tworzyć podklasy lub modyfikować komponenty bean za pomocą cglib, aby utworzyć proxy. @Transactionaljest jednym z przykładów użycia proxy do fasoli. AOP to kolejny.
Yoory N.
1
Chociaż czasami nie będziesz mieć więcej niż jednej klasy implementującej, nadal wolę deklarować moje metody w interfejsie. Innemu deweloperowi łatwiej będzie sprawdzić, jakie usługi są dostępne tylko po przejrzeniu deklaracji i dokumentacji bez martwienia się o implementację.
HFSDev
32

Zasadniczo adnotacje, takie jak @Service , @Repository , @Component itp., Wszystkie służą temu samemu celowi:

automatyczne wykrywanie podczas korzystania z konfiguracji opartej na adnotacjach i skanowania ścieżek klas.

Z mojego doświadczenia wynika, że ​​zawsze używam @Serviceadnotacji na interfejsach lub klas abstrakcyjnych i adnotacji, takich jak @Componenti @Repositorydo ich implementacji. @Componentadnotacja, której używam na tych zajęciach, które służą podstawowym celom, proste wiosenne fasolki, nic więcej. @Repositoryadnotacja, której używam w DAOwarstwie, np. jeśli muszę się komunikować z bazą danych, mieć jakieś transakcje itp.

Dlatego sugerowałbym dodanie adnotacji do interfejsu z @Serviceinnymi warstwami w zależności od funkcjonalności.

Paulius Matulionis
źródło
10
Czy możesz powiedzieć, jakie są różnice między interfejsami opisującymi a implementacjami z adnotacjami?
TheKojuEffect
27
Od docs Wiosna , „Ta adnotacja służy jako specjalizacji @Component, pozwalając na zajęcia wdrożeniowe być wykrywane poprzez skanowanie ścieżki klasy”, co sugeruje, że jest on przeznaczony do użycia w klasie realizacji.
nbrooks
1
@TheKojuEffect, ten post wyjaśnia szczegółowo różnicę między dodawaniem adnotacji do interfejsów a implementacjami - stackoverflow.com/questions/3120143/…
Mahesh
@ user3257644 Zwróć uwagę, że sugestie zawarte w odpowiedziach w tym poście odnoszą się konkretnie do adnotacji „@Transactional”, a nie ogólnie do wszystkich adnotacji.
Jonathan
3
Adnotacja @service na interfejsach nie ma żadnego wpływu, podobnie jak inne adnotacje stereotypowe. Wszystkie adnotacje stereotypowe należy umieszczać na klasach abstrakcyjnych lub konkretnych.
bigfoot
13

Kiedyś @Component, @Service, @Controllera @Repositoryadnotacje tylko na zajęciach, a nie na implementacji interfejsu. Ale @Autowiredadnotacja z interfejsami nadal działała dla mnie.

yalkris
źródło
7

Zaletą umieszczania adnotacji w @Service jest to, że daje wskazówkę, że jest to usługa. Nie wiem, czy jakakolwiek klasa implementująca domyślnie odziedziczy to adnotacje.

Wadą jest to, że łączysz swój interfejs z określonym frameworkiem, np. Spring, używając adnotacji specyficznej dla spring. Ponieważ interfejsy powinny być oddzielone od implementacji, nie sugerowałbym używania adnotacji specyficznych dla frameworka lub części obiektu interfejsu.

Kuldeep Tiwari
źródło
1
Myślę, że wszyscy słyszeliśmy wiele razy silny argument dotyczący sprzężenia, ale pamiętaj, że adnotacje mogą być obecne bez słoika, więc w zasadzie tak długo, jak połączenie jest na adnotacjach, nadal można je rozdzielić.
Niels Bech Nielsen
1

Jedną z korzyści wiosny jest łatwe przełączanie implementacji usługi (lub innej). W tym celu musisz dodać adnotację w interfejsie i zadeklarować zmienną w następujący sposób:

@Autowired
private MyInterface myVariable;

i nie :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

Podobnie jak w pierwszym przypadku, możesz aktywować implementację do wstrzyknięcia od momentu, gdy jest ona unikalna (tylko jedna klasa implementuje interfejs). W drugim przypadku musisz refaktoryzować cały kod (implementacja nowej klasy ma inną nazwę). W konsekwencji adnotacja musi znajdować się w interfejsie tak często, jak to możliwe. Ponadto serwery proxy JDK dobrze się do tego nadają: są tworzone i tworzone podczas uruchamiania aplikacji, ponieważ typ środowiska wykonawczego jest znany z góry, w przeciwieństwie do serwerów proxy CGlib.

François F.
źródło
4
„MyClassImplementationWhichImplementsMyInterface” LOL
inafalcao
Nie musisz dodawać adnotacji w interfejsie, aby pierwszy przykład zadziałał. Możesz @Servicedodawać adnotacje do implementacji i automatycznie podłączać interfejs. Spring sprawdzi każdy obiekt implementujący ten interfejs.
Marco
1

Postawiłbym @Servicena twoją klasę ale jako parametr wstawiłbym nazwę interfejsu do adnotacji np

interface ServiceOne {}

@Service("ServiceOne")
class ServiceOneImpl implements ServiceOne{}

W ten sposób uzyskasz wszystkie korzyści i nadal możesz wstrzyknąć interfejs, ale otrzymujesz klasę

@Autowired 
private ServiceOne serviceOne;

Twój interfejs nie jest więc powiązany ze strukturą sprężynową i możesz zmienić klasę w dowolnym momencie i nie musisz aktualizować wszystkich punktów wtrysku.

Więc gdybym chciał zmienić klasę implementacji, mógłbym po prostu dodać adnotacje do nowej klasy i usunąć z pierwszej, ale to wszystko, co należy zmienić. Jeśli wstrzykniesz klasę, możesz mieć dużo pracy, gdy będziesz chciał zmienić klasę impl.

user1239403
źródło
-1

Mówiąc prościej:

@Service to adnotacja stereotypowa dla warstwy usług .

@Repository jest adnotacji stereotypu na trwałość warstwy.

@Component to ogólna adnotacja stereotypowa, która mówi Springowi, aby utworzył instancję obiektu w kontekście aplikacji. Możliwe jest zdefiniowanie dowolnej nazwy dla instancji, domyślnie jest to nazwa klasy jako wielkość wielbłąda.

HughParker
źródło
3
Znaczenie tych adnotacji nie jest poszukiwane, ale GDZIE umieścić je w interfejsie lub jego implementacji.
nanosoft
-3

Istnieje 5 adnotacji, które można wykorzystać do zrobienia fasoli jarej. Wypisz poniżej odpowiedzi.

Czy naprawdę potrzebujesz interfejsu? Jeśli zamierzasz mieć jedną implementację dla każdego interfejsu usługi, po prostu jej unikaj, używaj tylko klasy. Oczywiście, jeśli nie masz RMI lub gdy wymagany jest interfejs proxy.

@Repository - służy do wstrzykiwania klas warstwy dao.

@Service - służy do wstrzykiwania klas warstwy usług. W warstwie usług może być również konieczne użycie adnotacji @Transactional do zarządzania transakcjami db.

@Controller - użyj dla kontrolerów warstwy frontendu, takich jak fasola zarządzana przez JSF wstrzykująca jako fasolka wiosenna.

@RestController - użyj dla kontrolerów spoczynku sprężynowego, pomoże ci to uniknąć za każdym razem umieszczania adnotacji @ResponseBody i @RequestBody w metodach odpoczynku.

@Component - użyj go w każdym innym przypadku, gdy potrzebujesz Wtryskiwać fasolkę, która nie jest klasą kontrolera, usługi lub dao

Artur Yolchyan
źródło
Tak, potrzebujesz interfejsu na granicach swoich warstw (takich jak warstwa dostępu do danych i warstwa usług). Umożliwiają one luźne łączenie modułów, które zawierają implementacje tych warstw. Bez nich klienci wspomnianych warstw muszą znać konkretne typy i trzeba je zmieniać, gdy np. Chcesz udekorować swój zestaw Basic√ z Caching Diplotop ...
Igand