Onde a anotação @Service deve ser mantida? Interface ou Implementação?

133

Estou desenvolvendo um aplicativo usando o Spring. Eu sou obrigado a usar a @Serviceanotação. Eu tenho ServiceIe ServiceImpltal que ServiceImpl implements ServiceI. Estou confuso aqui sobre onde devo guardar a @Serviceanotação.

Devo anotar a interface ou a implementação @Service? Quais são as diferenças entre essas duas abordagens?

TheKojuEffect
fonte
Esta é a minha resposta para uma postagem semelhante: stackoverflow.com/questions/38618995/…
Agustí Sánchez

Respostas:

140

Eu nunca coloco @Component(ou @Service...) em uma interface, porque isso torna a interface inútil. Deixe-me explicar o porquê.

reivindicação 1: se você possui uma interface, deseja usá-la para o tipo de ponto de injeção.

reivindicação 2: O objetivo de uma interface é definir um contrato que pode ser implementado por várias implementações. Por outro lado, você tem seu ponto de injeção ( @Autowired). Ter apenas uma interface e apenas uma classe que a implementa é (IMHO) inútil e viola o YAGNI .

fato: Quando você coloca:

  • @Component(ou @Service...) em uma interface,
  • tem várias classes que o implementam,
  • pelo menos duas classes se tornam Spring Beans, e
  • ter um ponto de injeção que use a interface para injeção baseada em tipo,

você receberá e NoUniqueBeanDefinitionException (ou você terá uma configuração muito especial, com Ambiente, Perfis ou Qualificadores ...)

Conclusão: Se você usa @Component(ou @Service...) em uma interface, deve violar pelo menos um dos dois clains. Portanto, acho que não é útil (exceto alguns cenários raros) colocar @Componentno nível da interface.


As interfaces Spring-Data-JPA Repository são algo completamente diferentes

Ralph
fonte
3
É muito interessante o que você escreve ... então qual é o caminho certo? Ele não está anotando a interface e dando a anotação de serviço para as implementações? O Spring ainda é capaz de fazer a fiação automática usando o tipo de interface? Qual é a sua resposta a esta> stackoverflow.com/questions/12899372/...
corlaez
3
Eu tenho uma pergunta, por que precisamos criar uma interface para a camada de serviço quando existe apenas uma classe para implementá-la? Eu já vi muitos projetos, eles têm camada de controlador, ** camada de serviço ( servicInterface , serviceInterfaceImpl ) e camada de repositório .
Yubaraj
4
@Yubaraj: ponto justo, mas sua pergunta é sobre um assunto bem diferente (para minha resposta, assumi a premissa de que existe uma interface e a pergunta não é sobre ter a interface, mas sobre onde colocar a anotação). Para sua pergunta: Quase não há razão para ter uma interface para uma classe de serviço de negócios que nunca terá duas implementações. (BTW: Contanto que você não esteja construindo uma API para outra pessoa, você sempre pode refatorar o código e apresentar a interface mais tarde, quando precisar)
Ralph
1
@Yubaraj, interfaces permitem criar proxies jdk leves e baseados em interface para beans quando necessário. Quando não há interface, o Spring precisa fazer uma subclasse ou modificar beans usando cglib para criar um proxy. @Transactionalé um dos exemplos em que um proxy para um bean é usado. AOP é outro.
Yoory N.
1
Embora algumas vezes você não tenha mais de uma classe de implementação, ainda prefiro declarar meus métodos em uma interface. Um desenvolvedor colaborador achará mais fácil verificar quais serviços estão disponíveis apenas olhando as declarações e a documentação sem se preocupar com a implementação.
HFSDev 29/05/19
32

Basicamente, anotações como @Service , @Repository , @Component etc., todas elas têm o mesmo objetivo:

detecção automática ao usar a configuração baseada em anotação e a verificação do caminho de classe.

Pela minha experiência, estou sempre usando @Serviceanotações nas interfaces ou classes abstratas e anotações como @Componente @Repositorypara sua implementação. @Componentanotação que estou usando nessas classes que servem a propósitos básicos, simples Spring beans, nada mais. @Repositoryanotação que estou usando na DAOcamada, por exemplo, se eu tiver que me comunicar com o banco de dados, ter algumas transações, etc.

Então, sugiro anotar sua interface com as @Serviceoutras camadas, dependendo da funcionalidade.

Paulius Matulionis
fonte
10
Você pode dizer quais são as diferenças entre as interfaces de anotação e as implementações de anotação?
TheKojuEffect
27
Nos documentos do Spring , "Esta anotação serve como uma especialização do @Component, permitindo que as classes de implementação sejam detectadas automaticamente por meio da varredura de caminho de classe", sugerindo que ela deve ser usada na classe de implementação.
Njords 02/07
1
@TheKojuEffect, Esta publicação explica em detalhes a diferença entre interfaces de anotação e implementações - stackoverflow.com/questions/3120143/…
Mahesh
@ user3257644 Observe que as sugestões dadas pelas respostas nessa postagem são referentes à anotação '@Transactional' especificamente, nem a todas as anotações em geral.
6137 Jonathan
3
A anotação @service nas interfaces não tem efeito, assim como as outras anotações de estereótipo. Toda anotação de estereótipo deve ser colocada em classes abstratas ou concretas.
bigfoot 26/03
13

Eu costumava @Component, @Service, @Controllere @Repositoryanotações apenas nas classes de implementação e não na interface. Mas a @Autowiredanotação com Interfaces ainda funcionava para mim.

yalkris
fonte
7

Prós de colocar anotações no @Service é que ele dá uma dica de que é um serviço. Não sei se alguma classe de implementação herdará por padrão essa anotação.

O lado negativo é que você está acoplando sua interface a uma estrutura específica, ou seja, Spring, usando anotações específicas da mola. Como as interfaces devem ser dissociadas da implementação, eu não sugeriria o uso de nenhuma anotação específica da estrutura ou parte do objeto da sua interface.

Kuldeep Tiwari
fonte
1
Acho que todos já ouvimos o argumento de acoplamento forte várias vezes, mas lembre-se de que as anotações podem estar presentes sem o jar, portanto, basicamente, desde que o acoplamento esteja em anotações, ele ainda pode ser dissociado.
Niels Bech Nielsen
1

Um benefício da primavera é alternar facilmente a implementação do Serviço (ou outro). Para isso, é necessário anotar na interface e declarar variáveis ​​assim:

@Autowired
private MyInterface myVariable;

e não :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

Como o primeiro caso, você pode ativar qual implementação injetar a partir do momento em que é exclusiva (apenas uma classe implementa a interface). No segundo caso, você precisa refatorar todo o seu código (a nova implementação de classe tem outro nome). Como conseqüência, a anotação precisa estar na interface o máximo possível. Além disso, os proxies JDK são adequados para isso: eles são criados e instanciados na inicialização do aplicativo porque o tipo de tempo de execução é conhecido antecipadamente, ao contrário dos proxies CGlib.

François F.
fonte
4
"MyClassImplementationWhichImplementsMyInterface" LOL
inafalcao
Você não precisa fazer anotações na interface para que o primeiro exemplo funcione. Você pode anotar com @Serviceuma implementação e conectar automaticamente a interface. O Spring verificará qualquer objeto que implemente essa interface.
Marco
1

Eu colocaria @Servicena sua classe, mas colocaria o nome da interface como parâmetro na anotação, por exemplo

interface ServiceOne {}

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

Ao fazer isso, você obtém todos os benefícios e ainda pode injetar a interface, mas obtém a classe

@Autowired 
private ServiceOne serviceOne;

Portanto, sua interface não está vinculada à estrutura da primavera e você pode alterar a classe a qualquer momento e não precisa atualizar todos os seus pontos de injeção.

Portanto, se eu quisesse alterar a classe de implementação, poderia apenas anotar a nova classe e removê-la da primeira, mas isso é tudo o que precisa ser alterado. Se você injetar a classe, poderá ter muito trabalho sempre que quiser alterar a classe impl.

user1239403
fonte
-1

Simplificando:

@Service é uma anotação de estereótipo para a camada de serviço .

@Repository é uma anotação estereótipo para a persistência camada.

@Component é uma anotação de estereótipo genérico usada para dizer ao Spring para criar uma instância do objeto no Contexto do Aplicativo. É possível definir qualquer nome para a instância, o padrão é o nome da classe como case camel.

HughParker
fonte
3
O significado dessas anotações não está sendo procurado, mas ONDE colocá-las na Interface ou em sua implementação.
Nanosoft 28/06
-3

Existem 5 anotações que podem ser usadas para fazer feijões de primavera. Listar abaixo das respostas.

Você realmente precisa de uma interface? Se você tiver uma implementação para cada interface de serviço, evite-a, use apenas classe. Obviamente, se você não possui RMI ou quando o proxy da interface é necessário.

@Repository - use para injetar suas classes de camadas dao.

@ Service - use para injetar suas classes de camada de serviço. Na camada de serviço também pode ser necessário usar a anotação @Transactional para o gerenciamento de transações do banco de dados.

@ Controlador - use para seus controladores de camada de front-end, como beans gerenciados por JSF, injetando como beans de primavera.

@RestController - use para controladores de descanso de primavera, isso ajudará você a evitar sempre colocar anotações @ResponseBody e @RequestBody em seus métodos de descanso.

@Component - use-o em qualquer outro caso, quando você precisar injetar Spring Bean, que não é da classe controller, service ou dao

Artur Yolchyan
fonte
Sim, você precisa de uma interface nas bordas das suas camadas (como camada de acesso a dados e camada de serviço). Eles permitem o acoplamento flexível de módulos que contêm as implementações dessas camadas. Sem eles, os clientes das camadas mencionadas precisam conhecer tipos concretos e você precisa alterá-los quando, por exemplo, deseja decorar seu BasicDao com CachingDao ...
Igand