Où doit-on conserver l'annotation @Service? Interface ou mise en œuvre?

133

Je développe une application avec Spring. Je suis obligé d'utiliser l' @Serviceannotation. J'ai ServiceIet ServiceImpltel que ServiceImpl implements ServiceI. Je ne sais pas où dois-je conserver l' @Serviceannotation.

Dois-je annoter l'interface ou l'implémentation avec @Service? Quelles sont les différences entre ces deux approches?

TheKojuEffect
la source
Voici ma réponse à un article similaire: stackoverflow.com/questions/38618995/…
Agustí Sánchez

Réponses:

140

Je n'ai jamais mis @Component(ou @Service, ...) sur une interface, car cela rend l'interface inutile. Laissez-moi vous expliquer pourquoi.

revendication 1: si vous avez une interface, vous souhaitez utiliser cette interface pour le type de point d'injection.

revendication 2: Le but d'une interface est de définir un contrat qui peut être implémenté par plusieurs implémentations. De l'autre côté, vous avez votre point d'injection ( @Autowired). Avoir juste une interface et une seule classe qui l'implémente, est (IMHO) inutile et viole YAGNI .

fait: Lorsque vous mettez:

  • @Component(ou @Service, ...) à une interface,
  • avoir plusieurs classes qui l'implémentent,
  • au moins deux classes deviennent Spring Beans, et
  • avoir un point d'injection qui utilise l'interface pour l'injection basée sur le type,

alors vous obtiendrez et NoUniqueBeanDefinitionException (ou vous avez une configuration de configurations très spéciale, avec environnement, profils ou qualificatifs ...)

Conclusion: Si vous utilisez @Component(ou @Service, ...) sur une interface, vous devez violer au moins l'un des deux clains. Par conséquent je pense qu'il n'est pas utile (sauf quelques rares scénarios) de le mettre @Componentau niveau de l'interface.


Les interfaces Spring-Data-JPA Repository sont quelque chose de complètement différent

Ralph
la source
3
C'est très intéressant ce que vous écrivez ... alors quelle est la bonne façon? N'est-ce pas du tout d'annoter l'interface et de donner l'annotation de service aux implémentations? Spring est-il toujours capable de se connecter automatiquement à l'aide du type d'interface? Quelle est votre réponse à cela> stackoverflow.com/questions/12899372/…
corlaez
3
J'ai une question, pourquoi avons-nous besoin de créer une interface pour la couche de service alors qu'il n'y a qu'une seule classe qui l'implémente? Je l' ai vu de nombreux projets, ils ont couche de contrôleur, couche de service ** ( de servicInterface , serviceInterfaceImpl ), et couche dépôt .
Yubaraj
4
@Yubaraj: bon point, mais votre question porte sur un tout autre sujet (pour ma réponse, j'ai pris l'hypothèse: qu'il y a une interface et que la question n'est pas d'avoir l'interface mais de savoir où placer l'annotation). Pour votre question: il n'y a presque aucune raison d'avoir une interface pour une classe de service métier qui n'aura jamais deux implémentations. (BTW: tant que vous ne construisez pas une api pour quelqu'un d'autre, vous pouvez toujours refactoriser votre code et introduire l'interface plus tard lorsque vous en avez besoin)
Ralph
1
@Yubaraj, les interfaces permettent de créer des proxys jdk légers basés sur des interfaces vers des beans lorsque cela est nécessaire. Quand il n'y a pas d'interface, spring doit faire des sous-classes ou modifier les beans en utilisant cglib pour créer un proxy. @Transactionalest l'un des exemples d'utilisation d'un proxy vers un bean. AOP en est un autre.
Yoory N.
1
Même si parfois vous n'aurez pas plus d'une classe d'implémentation, je préfère toujours déclarer mes méthodes dans une interface. Un collègue développeur trouvera plus facile de vérifier quels services sont disponibles uniquement en regardant les déclarations et la documentation sans se soucier de l'implémentation.
HFSDev
32

Fondamentalement, des annotations telles que @Service , @Repository , @Component , etc., elles ont toutes le même objectif:

détection automatique lors de l'utilisation de la configuration basée sur les annotations et de l'analyse du chemin de classe.

D'après mon expérience, j'utilise toujours des @Serviceannotations sur les interfaces ou des classes abstraites et des annotations comme @Componentet @Repositorypour leur implémentation. @Componentannotation que j'utilise sur ces classes qui servent des objectifs basiques, de simples Spring beans, rien de plus. @Repositoryannotation que j'utilise dans la DAOcouche, par exemple si je dois communiquer avec la base de données, effectuer des transactions, etc.

Je suggérerais donc d'annoter votre interface avec les @Servicecouches et d'autres en fonction de la fonctionnalité.

Paulius Matulionis
la source
10
Pouvez-vous dire quelles sont les différences entre les interfaces d'annotation et les implémentations d'annotation?
TheKojuEffect
27
D'après la documentation Spring , «Cette annotation sert de spécialisation de @Component, permettant aux classes d'implémentation d'être détectées automatiquement via l'analyse du chemin de classe», suggérant qu'elle est destinée à être utilisée sur la classe d'implémentation.
nbrooks
1
@TheKojuEffect, Cet article explique en détail la différence entre les interfaces d'annotation et les implémentations - stackoverflow.com/questions/3120143/…
Mahesh
@ user3257644 Notez simplement que les suggestions données par les réponses dans ce message concernent spécifiquement l'annotation «@Transactional», pas toutes les annotations en général.
Jonathan
3
L'annotation @service sur les interfaces n'a aucun effet, tout comme les autres annotations stéréotypées. Toutes les annotations de stéréotypes doivent être placées sur des classes abstraites ou concrètes.
bigfoot
13

Je @Component, @Service, @Controlleret les @Repositoryannotations que sur les classes de mise en œuvre et non pas sur l'interface. Mais l' @Autowiredannotation avec les interfaces fonctionnait toujours pour moi.

yalkris
la source
7

L'avantage de mettre une annotation sur @Service est que cela donne un indice qu'il s'agit d'un service. Je ne sais pas si une classe d'implémentation héritera par défaut de cette annoation.

L'inconvénient est que vous associez votre interface à un cadre spécifique, à savoir Spring, en utilisant une annotation spécifique au ressort. Comme les interfaces sont censées être découplées de l'implémentation, je ne suggérerais pas d'utiliser des annotations spécifiques au framework ou une partie objet de votre interface.

Kuldeep Tiwari
la source
1
Je pense que nous avons tous entendu l'argument du couplage fort à plusieurs reprises, mais rappelez-vous que les annotations peuvent être présentes sans le pot, donc fondamentalement, tant que votre couplage est sur des annotations, il peut toujours être découplé.
Niels Bech Nielsen
1

L'un des avantages du ressort est de changer facilement la mise en œuvre du service (ou autre). Pour cela, vous devez annoter sur l'interface et déclarer une variable comme ceci:

@Autowired
private MyInterface myVariable;

et pas :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

Comme dans le premier cas, vous pouvez activer quelle implémentation injecter à partir du moment où elle est unique (une seule classe implémente l'interface). Dans le second cas, vous devez refactoriser tout votre code (la nouvelle implémentation de classe a un autre nom). En conséquence, l'annotation doit être autant que possible sur l'interface. De plus, les proxies JDK sont bien adaptés pour cela: ils sont créés et instanciés au démarrage de l'application car le type d'exécution est connu d'avance, contrairement aux proxies CGlib.

François F.
la source
4
"MyClassImplementationWhichImplementsMyInterface" LOL
inafalcao
Vous n'avez pas besoin d'annoter sur l'interface pour que le premier exemple fonctionne. Vous pouvez annoter avec @Serviceune implémentation et activer automatiquement l'interface. Spring recherchera tout objet implémentant cette interface.
Marco
1

Je mettrais @Servicevotre classe mais mettre le nom de l'interface comme paramètre de l'annotation par exemple

interface ServiceOne {}

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

En faisant cela, vous obtenez tous les avantages et pouvez toujours injecter l'interface mais obtenir la classe

@Autowired 
private ServiceOne serviceOne;

Ainsi, votre interface n'est pas liée au framework Spring et vous pouvez changer de classe à tout moment et ne pas avoir à mettre à jour tous vos points d'injection.

Donc, si je voulais changer la classe d'implémentation, je pourrais simplement annoter la nouvelle classe et supprimer de la première, mais c'est tout ce qu'il faut changer. Si vous injectez la classe, vous pourriez avoir beaucoup de travail quand vous voulez changer la classe impl.

user1239403
la source
-1

Pour le dire simplement:

@Service est une annotation Stéréotype pour la couche de service .

@Repository est une annotation de stéréotype pour la persistance couche.

@Component est une annotation stéréotype générique utilisée pour indiquer à Spring de créer une instance de l'objet dans le contexte d'application. Il est possible de définir n'importe quel nom pour l'instance, la valeur par défaut est le nom de la classe comme cas camel.

HughParker
la source
3
La signification de ces annotations n'est pas recherchée mais O put les mettre sur Interface ou son implémentation.
nanosoft
-3

Il y a 5 annotations qui pourraient être utilisées pour faire des haricots de printemps. Liste ci-dessous des réponses.

Avez-vous vraiment besoin d'une interface? Si vous prévoyez d'avoir une implémentation pour chaque interface de service, évitez-la, utilisez uniquement la classe. Bien sûr, si vous n'avez pas RMI ou lorsqu'un proxy d'interface est requis.

@Repository - à utiliser pour injecter vos classes de couche DAO.

@Service - à utiliser pour injecter vos classes de couche de service. Dans la couche de service, vous devrez peut-être également utiliser l'annotation @Transactional pour la gestion des transactions db.

@Controller - à utiliser pour vos contrôleurs de couche frontale, tels que les beans gérés JSF injectés en tant que beans spring.

@RestController - à utiliser pour les contrôleurs de repos à ressort, cela vous aiderait à éviter à chaque fois de mettre des annotations @ResponseBody et @RequestBody dans vos méthodes de repos.

@Component - utilisez-le dans tous les autres cas lorsque vous avez besoin d'injecter un haricot de printemps qui n'est pas une classe de contrôleur, de service ou de DAO

Artur Yolchyan
la source
Oui, vous avez besoin d'une interface sur les frontières de vos couches (comme la couche d'accès aux données et la couche de service). Ils permettent un couplage lâche des modules qui contiennent ces implémentations de couches. Sans eux, les clients des couches mentionnées doivent connaître les types de béton et vous devez les changer lorsque, par exemple, vous voulez décorer votre BasicDao avec CachingDao ...
Igand