Wo soll die @ Service-Annotation aufbewahrt werden? Schnittstelle oder Implementierung?

130

Ich entwickle eine Anwendung mit Spring. Ich muss die @ServiceAnmerkung verwenden. Ich habe ServiceIund ServiceImplso das ServiceImpl implements ServiceI. Ich bin hier verwirrt, wo ich die @ServiceAnmerkung aufbewahren soll.

Soll ich die Schnittstelle oder die Implementierung mit kommentieren @Service? Was sind die Unterschiede zwischen diesen beiden Ansätzen?

TheKojuEffect
quelle
Dies ist meine Antwort auf einen ähnlichen Beitrag: stackoverflow.com/questions/38618995/…
Agustí Sánchez

Antworten:

139

Ich habe nie @Component(oder @Service...) an eine Schnittstelle gesetzt, weil dies die Schnittstelle unbrauchbar macht. Lassen Sie mich erklären, warum.

Anspruch 1: Wenn Sie eine Schnittstelle haben, möchten Sie diese Schnittstelle für den Injektionspunkttyp verwenden.

Anspruch 2: Der Zweck einer Schnittstelle besteht darin, einen Vertrag zu definieren, der von mehreren Implementierungen implementiert werden kann. Auf der anderen Seite haben Sie Ihren Injektionspunkt ( @Autowired). Nur eine Schnittstelle und nur eine Klasse zu haben, die sie implementiert, ist (IMHO) nutzlos und verstößt gegen YAGNI .

Tatsache: Wenn Sie setzen:

  • @Component(oder @Service...) an einer Schnittstelle,
  • haben mehrere Klassen, die es implementiert,
  • Mindestens zwei Klassen werden zu Frühlingsbohnen
  • einen Injektionspunkt haben, der die Schnittstelle für die typbasierte Injektion verwendet,

dann erhalten Sie und NoUniqueBeanDefinitionException (oder Sie haben ein ganz spezielles Konfigurationssetup mit Umgebung, Profilen oder Qualifikationsmerkmalen ...)

Schlussfolgerung: Wenn Sie an einer Schnittstelle @Component(oder @Service...) verwenden, müssen Sie mindestens eine der beiden Clains verletzen. Daher denke ich, dass es nicht nützlich ist (mit Ausnahme einiger seltener Szenarien), @Componentauf Schnittstellenebene zu setzen .


Spring-Data-JPA-Repository-Schnittstellen sind etwas völlig anderes

Ralph
quelle
3
Es ist sehr interessant, was du schreibst ... also was ist der richtige Weg? Kommentiert es die Schnittstelle überhaupt nicht und gibt den Implementierungen die Service-Annotation? Kann Spring den Schnittstellentyp weiterhin automatisch verdrahten? Was ist Ihre Antwort auf diese> stackoverflow.com/questions/12899372/…
corlaez
3
Ich habe eine Frage, warum müssen wir eine Schnittstelle für die Serviceschicht erstellen, wenn nur eine Klasse diese implementiert? Ich habe viele Projekte gesehen, sie haben Controller-Schicht, ** Service-Schicht ( servicInterface , serviceInterfaceImpl ) und Repository-Schicht .
Yubaraj
4
@Yubaraj: Fairer Punkt, aber Ihre Frage bezieht sich auf ein ganz anderes Thema (für meine Antwort ging ich davon aus, dass es eine Schnittstelle gibt und die Frage nicht die Schnittstelle, sondern den Ort, an dem die Anmerkung platziert werden soll). Für Ihre Frage: Es gibt fast keinen Grund, eine Schnittstelle für eine Business Service-Klasse zu haben, die niemals zwei Implementierungen haben wird. (Übrigens: Solange Sie keine API für eine andere Person erstellen, können Sie Ihren Code jederzeit umgestalten und die Benutzeroberfläche später bei Bedarf einführen.)
Ralph
1
@Yubaraj, Schnittstellen ermöglichen es, bei Bedarf leichtgewichtige, auf Schnittstellen basierende JDK-Proxys für Beans zu erstellen. Wenn keine Schnittstelle vorhanden ist, muss spring mithilfe von cglib Unterklassen erstellen oder Beans ändern, um einen Proxy zu erstellen. @Transactionalist eines der Beispiele, bei denen ein Proxy für eine Bean verwendet wird. AOP ist eine andere.
Yoory N.
1
Auch wenn Sie manchmal nicht mehr als eine Implementierungsklasse haben, deklariere ich meine Methoden lieber in einer Schnittstelle. Ein anderer Entwickler kann leichter überprüfen, welche Dienste verfügbar sind, indem er sich die Deklarationen und die Dokumentation ansieht, ohne sich um die Implementierung zu kümmern.
HFSDev
32

Grundsätzlich dienen Anmerkungen wie @Service , @Repository , @Component usw. demselben Zweck:

Automatische Erkennung bei Verwendung der annotationsbasierten Konfiguration und des Scannens von Klassenpfaden.

Aus meiner Erfahrung verwende ich immer @ServiceAnnotationen auf den Schnittstellen oder abstrakten Klassen und Annotationen wie @Componentund @Repositoryfür deren Implementierung. @ComponentAnmerkung, die ich für jene Klassen verwende, die grundlegenden Zwecken dienen, einfache Frühlingsbohnen, nichts weiter. @RepositoryAnmerkung, die ich in der DAOEbene verwende, z. B. wenn ich mit der Datenbank kommunizieren muss, einige Transaktionen habe usw.

Daher würde ich vorschlagen, Ihre Benutzeroberfläche @Serviceje nach Funktionalität mit den und anderen Ebenen zu versehen .

Paulius Matulionis
quelle
10
Können Sie die Unterschiede zwischen Annotationsschnittstellen und Annotationsimplementierungen erkennen?
TheKojuEffect
27
In den Spring-Dokumenten heißt es: "Diese Annotation dient als Spezialisierung von @Component und ermöglicht die automatische Erkennung von Implementierungsklassen durch das Scannen von Klassenpfaden", was darauf hindeutet, dass sie für die Implementierungsklasse verwendet werden soll.
Nbrooks
1
@ TheKojuEffect, Dieser Beitrag erklärt im Detail den Unterschied zwischen kommentierenden
Mahesh
@ user3257644 Beachten Sie nur, dass sich die Vorschläge in den Antworten in diesem Beitrag auf die Annotation '@Transactional' beziehen, nicht auf alle Annotationen im Allgemeinen.
Jonathan
3
Die @ service-Annotation auf Schnittstellen hat keine Auswirkung, genau wie die anderen stereotypen Annotationen. Alle stereotypen Anmerkungen sollten entweder abstrakten oder konkreten Klassen zugeordnet werden.
Bigfoot
13

Früher habe ich @Component, @Service, @Controllerund @RepositoryAnnotationen nur auf den Implementierungsklassen und nicht auf der Schnittstelle. Aber die @AutowiredAnnotation mit Interfaces hat bei mir immer noch funktioniert.

Yalkris
quelle
7

Das Hinzufügen von Anmerkungen zu @Service hat den Vorteil, dass es einen Hinweis darauf gibt, dass es sich um einen Dienst handelt. Ich weiß nicht, ob eine implementierende Klasse diese Annoation standardmäßig erbt.

Der Nachteil ist, dass Sie Ihre Schnittstelle mit einem bestimmten Framework, z. B. Spring, koppeln, indem Sie eine federspezifische Anmerkung verwenden. Da Schnittstellen von der Implementierung entkoppelt werden sollen, würde ich nicht empfehlen, Framework-spezifische Anmerkungen oder Objektteile Ihrer Schnittstelle zu verwenden.

Kuldeep Tiwari
quelle
1
Ich denke, wir haben alle das starke Kopplungsargument mehrmals gehört, aber denken Sie daran, dass Anmerkungen ohne das Glas vorhanden sein können. Solange Ihre Kopplung auf Anmerkungen basiert, kann sie dennoch entkoppelt werden.
Niels Bech Nielsen
1

Ein Vorteil der Feder besteht darin, dass die Service- (oder andere) Implementierung einfach gewechselt werden kann. Dazu müssen Sie die Schnittstelle mit Anmerkungen versehen und die Variable wie folgt deklarieren:

@Autowired
private MyInterface myVariable;

und nicht :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

Wie im ersten Fall können Sie die zu injizierende Implementierung ab dem Moment aktivieren, in dem sie eindeutig ist (nur eine Klasse implementiert die Schnittstelle). Im zweiten Fall müssen Sie Ihren gesamten Code umgestalten (die neue Klassenimplementierung hat einen anderen Namen). Infolgedessen muss sich die Anmerkung so weit wie möglich auf der Schnittstelle befinden. Darüber hinaus sind JDK-Proxys dafür gut geeignet: Sie werden beim Start der Anwendung erstellt und instanziiert, da der Laufzeittyp im Gegensatz zu CGlib-Proxys im Voraus bekannt ist.

François F.
quelle
4
"MyClassImplementationWhichImplementsMyInterface" LOL
inafalcao
Sie müssen keine Anmerkungen auf der Benutzeroberfläche machen, damit das erste Beispiel funktioniert. Sie können mit @Serviceeiner Implementierung Anmerkungen machen und die Schnittstelle automatisch verdrahten. Spring sucht nach Objekten, die diese Schnittstelle implementieren.
Marco
1

Ich würde @ServiceIhre Klasse anlegen, aber den Namen der Schnittstelle als Parameter für die Anmerkung angeben, z

interface ServiceOne {}

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

Auf diese Weise erhalten Sie alle Vorteile und können die Schnittstelle trotzdem einspeisen, aber die Klasse erhalten

@Autowired 
private ServiceOne serviceOne;

Ihre Schnittstelle ist also nicht an das Federgerüst gebunden, und Sie können die Klasse jederzeit ändern, ohne alle Injektionspunkte aktualisieren zu müssen.

Wenn ich also die Implementierungsklasse ändern wollte, konnte ich die neue Klasse einfach mit Anmerkungen versehen und aus der ersten entfernen, aber das ist alles, was geändert werden muss. Wenn Sie die Klasse injizieren, können Sie viel Arbeit haben, wann immer Sie die impl-Klasse ändern möchten.

user1239403
quelle
-1

Einfach gesagt:

@Service ist eine Stereotype-Annotation für die Service- Schicht.

@Repository ist ein Klischee Annotation für die Persistenz Schicht.

@Component ist eine generische stereotype Annotation, mit der Spring angewiesen wird , eine Instanz des Objekts im Anwendungskontext zu erstellen. Es ist möglich, einen beliebigen Namen für die Instanz zu definieren. Der Standardwert ist der Klassenname als Kamelfall.

HughParker
quelle
3
Die Bedeutung dieser Anmerkungen wird nicht gesucht, sondern wo sie auf der Schnittstelle oder ihrer Implementierung abgelegt werden sollen.
Nanosoft
-3

Es gibt 5 Anmerkungen, die zur Herstellung von Frühlingsbohnen verwendet werden können. Liste der Antworten unten.

Benötigen Sie wirklich eine Schnittstelle? Wenn Sie für jede Serviceschnittstelle eine Implementierung haben möchten, vermeiden Sie diese einfach und verwenden Sie nur die Klasse. Natürlich, wenn Sie kein RMI haben oder wenn ein Schnittstellen-Proxy erforderlich ist.

@Repository - Zum Injizieren Ihrer Dao-Layer-Klassen.

@Service - Zum Einfügen Ihrer Service-Layer-Klassen. In der Service-Schicht müssen Sie möglicherweise auch die @ Transactional-Annotation für die Datenbank-Transaktionsverwaltung verwenden.

@Controller - Wird für Ihre Frontend-Layer-Controller verwendet, z. B. JSF-verwaltete Beans, die als Spring Beans injiziert werden.

@RestController - Wird für Federruhe-Steuerungen verwendet. Dies würde Ihnen helfen, jedes Mal zu vermeiden, dass @ResponseBody- und @RequestBody-Anmerkungen in Ihre Ruhemethoden eingefügt werden.

@Component - Verwenden Sie es in jedem anderen Fall, wenn Sie Spring Bean injizieren müssen, bei dem es sich nicht um eine Controller-, Service- oder Dao-Klasse handelt

Artur Yolchyan
quelle
Ja, Sie benötigen eine Schnittstelle an den Rändern Ihrer Ebenen (wie Datenzugriffsschicht und Serviceschicht). Sie ermöglichen die lose Kopplung von Modulen, die diese Ebenenimplementierungen enthalten. Ohne sie müssen die Kunden der genannten Schichten konkrete Typen kennen und Sie müssen sie ändern, wenn Sie beispielsweise Ihr BasicDao mit CachingDao dekorieren möchten ...
Igand