Dove dovrebbe essere conservata l'annotazione @Service? Interfaccia o implementazione?


133

Sto sviluppando un'applicazione usando Spring. Mi viene richiesto di utilizzare l' @Serviceannotazione. Ho ServiceIe ServiceImpltale che ServiceImpl implements ServiceI. Sono confuso qui su dove dovrei tenere il@Service annotazione.

Devo annotare l'interfaccia o l'implementazione con @Service? Quali sono le differenze tra questi due approcci?


Questa è la mia risposta a un post simile: stackoverflow.com/questions/38618995/…
Agustí Sánchez

Risposte:


140

Non ho mai messo @Component(o @Service, ...) un'interfaccia, perché ciò rende l'interfaccia inutile. Lasciami spiegare perché.

rivendicazione 1: se si dispone di un'interfaccia, si desidera utilizzare tale interfaccia per il tipo di punto di iniezione.

rivendicazione 2: lo scopo di un'interfaccia è quello di definire un contratto che può essere implementato da diverse implementazioni. Dall'altro lato hai il punto di iniezione ( @Autowired). Avere solo un'interfaccia e una sola classe che la implementa, è (IMHO) inutile e viola YAGNI .

fatto: quando metti:

  • @Component(o @Service, ...) su un'interfaccia,
  • hanno più classi che lo implementano,
  • almeno due classi diventano Spring Beans e
  • avere un punto di iniezione che utilizza l'interfaccia per l'iniezione basata sul tipo,

poi otterrai e NoUniqueBeanDefinitionException (o hai una configurazione molto speciale delle configurazioni, con ambiente, profili o qualificatori ...)

Conclusione: se si utilizza @Component(o @Service, ...) a un'interfaccia, è necessario violare almeno una delle due claine. Pertanto penso che non sia utile (tranne alcuni scenari rari) da mettere @Componenta livello di interfaccia.


Le interfacce del repository Spring-Data-JPA sono qualcosa di completamente diverso


3
È molto interessante quello che scrivi ... quindi qual è la strada giusta? Non sta annotando affatto l'interfaccia e dando l'annotazione del servizio alle implementazioni? Spring è ancora in grado di autowiring usando il tipo di interfaccia? Qual è la sua risposta a questa> stackoverflow.com/questions/12899372/...
corlaez

3
Ho una domanda, perché dobbiamo creare un'interfaccia per il livello di servizio quando esiste solo una classe per implementarla? Ho visto molti progetti, hanno strato di controllo, livello di servizio ** ( servicInterface , serviceInterfaceImpl ), e strato di repository .
Yubaraj

4
@Yubaraj: punto giusto, ma la tua domanda riguarda un altro argomento (per la mia risposta ho assunto il presupposto: che esiste un'interfaccia e la domanda non è di avere l'interfaccia ma di dove posizionare l'annotazione). Per la tua domanda: non c'è quasi motivo di avere un'interfaccia per una classe di servizio aziendale che non avrà mai due implementazioni. (A proposito: fintanto che non stai costruendo un API per qualcun altro, puoi sempre refactoring il codice e introdurre l'interfaccia in seguito quando ne hai bisogno)
Ralph

1
@Yubaraj, le interfacce consentono di creare proxy jdk basati su interfaccia leggera per i bean quando necessario. Quando non c'è interfaccia, spring deve eseguire la sottoclasse o modificare i bean usando cglib per creare un proxy. @Transactionalè uno degli esempi in cui viene utilizzato un proxy per un bean. AOP è un altro.
Yoory N.

1
Anche se a volte non avrai più di una classe di implementazione, preferisco comunque dichiarare i miei metodi in un'interfaccia. Un collega sviluppatore troverà più facile controllare quali servizi sono disponibili solo guardando le dichiarazioni e la documentazione senza preoccuparsi dell'implementazione.
HFSDev

32

Fondamentalmente le annotazioni come @Service , @Repository , @Component , ecc. Servono tutte allo stesso scopo:

rilevamento automatico quando si utilizza la configurazione basata su annotazioni e la scansione del percorso di classe.

Dalla mia esperienza utilizzo sempre le @Serviceannotazioni sulle interfacce o le classi astratte e le annotazioni come @Componente @Repositoryper la loro implementazione. @Componentannotazione che sto usando su quelle classi che servono a scopi di base, semplici fagioli primavera, niente di più. @Repositoryannotazione che sto usando inDAO layer, ad esempio se devo comunicare con il database, avere delle transazioni, ecc.

Quindi suggerirei di annotare la tua interfaccia con @Servicee altri livelli a seconda della funzionalità.


10
Puoi dire quali sono le differenze tra l'annotazione delle interfacce e l'annotazione delle implementazioni?
TheKojuEffect

27
Dai documenti di Spring , "Questa annotazione funge da specializzazione di @Component, che consente di rilevare automaticamente le classi di implementazione tramite la scansione del percorso di classe", suggerendo che deve essere utilizzata sulla classe di implementazione.
nbrooks

1
@TheKojuEffect, questo post spiega in dettaglio la differenza tra l'annotazione delle interfacce rispetto alle implementazioni - stackoverflow.com/questions/3120143/…
Mahesh

@ user3257644 Tieni presente che i suggerimenti forniti dalle risposte in quel post riguardano in particolare l'annotazione "@Transactional", non tutte le annotazioni in generale.
Jonathan,

3
L'annotazione @service sulle interfacce non ha alcun effetto, proprio come le altre annotazioni stereotipate. Tutte le annotazioni degli stereotipi devono essere inserite in classi astratte o concrete.
bigfoot,

13

Ho usato @Component, @Service, @Controllere @Repositoryle annotazioni solo sulle classi di implementazione e non sull'interfaccia. Ma l' @Autowiredannotazione con le interfacce ha funzionato ancora per me.


7

I pro di mettere annotazioni su @Service è che dà un suggerimento che è un servizio. Non so se nessuna classe di implementazione erediterà questo disturbo per impostazione predefinita.

Il lato negativo è che stai accoppiando la tua interfaccia con un framework specifico, ad esempio Spring, usando l'annotazione specifica per spring. Poiché le interfacce dovrebbero essere disaccoppiate dall'implementazione, non suggerirei di usare Annotazioni specifiche del framework o parte dell'oggetto dell'interfaccia.


1
Penso che tutti abbiamo sentito più volte l'argomento dell'accoppiamento forte, ma ricorda che le annotazioni possono essere presenti senza il barattolo, quindi in pratica finché il tuo accoppiamento è su annotazioni può ancora essere disaccoppiato.
Niels Bech Nielsen,

1

Uno dei vantaggi di Spring è di passare facilmente all'implementazione del servizio (o di altro tipo). Per questo, è necessario annotare sull'interfaccia e dichiarare la variabile in questo modo:

@Autowired
private MyInterface myVariable;

e non :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

Come nel primo caso, puoi attivare quale implementazione iniettare dal momento in cui è unica (solo una classe implementa l'interfaccia). Nel secondo caso, devi refactificare tutto il tuo codice (l'implementazione della nuova classe ha un altro nome). Di conseguenza, l'annotazione deve essere il più possibile nell'interfaccia. Inoltre, i proxy JDK sono adatti per questo: sono creati e istanziati all'avvio dell'applicazione perché il tipo di runtime è noto in anticipo, contrariamente ai proxy CGlib.


4
"MyClassImplementationWhichImplementsMyInterface" LOL
inafalcao

Non è necessario annotare sull'interfaccia perché il primo esempio funzioni. È possibile annotare con @Serviceun'implementazione e autowire l'interfaccia. Spring verificherà la presenza di eventuali oggetti che implementano questa interfaccia.
Marco,

1

Vorrei mettere la @Servicetua classe ma mettere il nome dell'interfaccia come parametro per l'annotazione ad es

interface ServiceOne {}

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

In questo modo ottieni tutti i vantaggi e puoi ancora iniettare l'interfaccia ma ottenere la classe

@Autowired 
private ServiceOne serviceOne;

Quindi la tua interfaccia non è legata al framework Spring e puoi cambiare classe in qualsiasi momento e non devi aggiornare tutti i tuoi punti di iniezione.

Quindi, se volessi cambiare la classe di implementazione, potrei semplicemente annotare la nuova classe e rimuoverla dalla prima, ma è tutto ciò che è necessario modificare. Se inietti la classe, potresti avere molto lavoro quando vuoi cambiare la classe impl.


-1

Per dirla semplicemente:

@Service è un'annotazione stereotipata per il livello di servizio .

@Repository è un'annotazione stereotipo per la persistenza strato.

@Component è un'annotazione stereotipata generica utilizzata per dire a Spring di creare un'istanza dell'oggetto nel contesto dell'applicazione. È possibile definire qualsiasi nome per l'istanza, il valore predefinito è il nome della classe come caso cammello.


3
Non si cerca il significato di queste annotazioni ma DOVE metterle su Interface o sulla sua implementazione.
nanosoft,

-3

Ci sono 5 annotazioni che potrebbero essere utilizzate per creare fagioli di primavera. Elenco sotto di risposte.

Hai davvero bisogno di un'interfaccia? Se hai intenzione di avere un'implementazione per ogni interfaccia di servizio, evitala, usa solo la classe. Naturalmente, se non si dispone di RMI o quando è richiesto il proxy dell'interfaccia.

@Repository: utilizzare per iniettare le classi di livelli dao.

@Servizio: utilizzare per iniettare le classi del livello di servizio. Anche nel livello di servizio potrebbe essere necessario utilizzare l'annotazione transazionale per la gestione delle transazioni db.

@Controller: utilizzare per i controller di livello front-end, come i bean gestiti JSF che iniettano come bean di primavera.

@RestController - utilizzare per i controller di riposo a molla, questo ti aiuterebbe ad evitare ogni volta di inserire le annotazioni @ResponseBody e @RequestBody nei tuoi metodi di riposo.

@Component: utilizzalo in qualsiasi altro caso quando devi iniettare il bean di primavera che non è controller, servizio o classe dao


Sì, è necessaria un'interfaccia sui bordi dei livelli (come il livello di accesso ai dati e il livello di servizio). Consentono l'accoppiamento libero di moduli che contengono implementazioni di strati. Senza di loro, i clienti dei livelli menzionati devono conoscere tipi concreti e devi cambiarli quando, diciamo, vuoi decorare il tuo BasicDao con CachingDao ...
Igand
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.