¿Dónde se debe guardar la anotación @Service? Interfaz o implementación?

133

Estoy desarrollando una aplicación usando Spring. Estoy obligado a usar la @Serviceanotación. Tengo ServiceIy ServiceImpltal que ServiceImpl implements ServiceI. Aquí estoy confundido sobre dónde debo guardar la @Serviceanotación.

¿Debo anotar la interfaz o la implementación con @Service? ¿Cuáles son las diferencias entre estos dos enfoques?

El efecto Koju
fuente
Esta es mi respuesta a una publicación similar: stackoverflow.com/questions/38618995/…
Agustí Sánchez

Respuestas:

140

Nunca puse @Component(o @Service...) en una interfaz, porque esto hace que la interfaz sea inútil. Déjame explicarte por qué.

reclamo 1: Si tiene una interfaz, entonces desea usar esa interfaz para el tipo de punto de inyección.

reclamo 2: El propósito de una interfaz es que defina un contrato que pueda implementarse mediante varias implementaciones. En el otro lado tienes tu punto de inyección ( @Autowired). Tener solo una interfaz y solo una clase que lo implemente, es (en mi humilde opinión) inútil, y viola YAGNI .

hecho: cuando pones:

  • @Component(o @Service...) en una interfaz,
  • tener múltiples clases que lo implementen,
  • al menos dos clases se convierten en Spring Beans, y
  • tener un punto de inyección que use la interfaz para inyección basada en tipos,

entonces obtendrá y NoUniqueBeanDefinitionException (o tiene una configuración de configuraciones muy especial, con Entorno, Perfiles o Calificadores ...)

Conclusión: Si usa @Component(o @Service...) en una interfaz, entonces debe violar al menos una de las dos claves. Por lo tanto, creo que no es útil (excepto algunos escenarios raros) poner @Componenta nivel de interfaz.


Las interfaces Spring-Data-JPA Repository son algo completamente diferente

Ralph
fuente
3
Es muy interesante lo que escribes ... ¿cuál es la forma correcta? ¿No está anotando la interfaz en absoluto y dando la anotación del Servicio a las implementaciones? ¿Spring todavía es capaz de realizar el cableado automático utilizando el tipo de interfaz? ¿Cuál es su respuesta a esta> stackoverflow.com/questions/12899372/...
corlaez
3
Tengo una pregunta, ¿por qué necesitamos crear una interfaz para la capa de servicio cuando solo hay una clase para implementarla? He visto muchos proyectos, tienen capa de controlador, ** capa de servicio ( servicInterface , serviceInterfaceImpl ) y capa de repositorio .
Yubaraj
44
@Yubaraj: punto justo, pero su pregunta es sobre un tema bastante diferente (para mi respuesta, asumí que existe una interfaz y la pregunta no es sobre tener la interfaz sino sobre dónde colocar la anotación). Para su pregunta: casi no hay razón para tener una interfaz para una clase de servicio empresarial que nunca tendrá dos implementaciones. (Por cierto: siempre que no esté creando una API para otra persona, siempre puede refactorizar su código e introducir la interfaz más adelante cuando lo necesite)
Ralph
1
@Yubaraj, las interfaces permiten hacer proxys jdk ligeros basados ​​en interfaz para beans cuando sea necesario. Cuando no hay interfaz, spring tiene que hacer subclases o modificar beans usando cglib para hacer un proxy. @Transactionales uno de los ejemplos en los que se usa un proxy para un bean. AOP es otro.
Yoory N.
1
Aunque a veces no tendrá más de una clase de implementación, prefiero declarar mis métodos en una interfaz. A un desarrollador desarrollador le resultará más fácil verificar qué servicios están disponibles solo mirando las declaraciones y la documentación sin preocuparse por la implementación.
HFSDev
32

Básicamente, las anotaciones como @Service , @Repository , @Component , etc. todas tienen el mismo propósito:

detección automática cuando se utiliza la configuración basada en anotaciones y el escaneo de classpath.

Desde mi experiencia, siempre estoy usando @Serviceanotaciones en las interfaces o clases abstractas y anotaciones como @Componenty @Repositorypara su implementación. @Componentanotación que estoy usando en esas clases que sirve para propósitos básicos, simples Spring beans, nada más. @Repositoryanotación que estoy usando en la DAOcapa, por ejemplo, si tengo que comunicarme a la base de datos, realizar algunas transacciones, etc.

Por lo tanto, sugeriría anotar su interfaz con las @Servicecapas y otras dependiendo de la funcionalidad.

Paulius Matulionis
fuente
10
¿Puedes decir cuáles son las diferencias entre las interfaces de anotación y las implementaciones de anotación?
TheKojuEffect
27
De los documentos de Spring , "Esta anotación sirve como una especialización de @Component, permitiendo que las clases de implementación se detecten automáticamente a través del escaneo de classpath", lo que sugiere que está destinada a ser utilizada en la clase de implementación.
nbrooks
1
@TheKojuEffect, esta publicación explica en detalle la diferencia entre las interfaces de anotación y las implementaciones - stackoverflow.com/questions/3120143/…
Mahesh
@ user3257644 Solo tenga en cuenta que las sugerencias dadas por las respuestas en esa publicación se refieren específicamente a la anotación '@Transactional', no a todas las anotaciones en general.
Jonathan
3
La anotación @service en las interfaces no tiene ningún efecto, al igual que las otras anotaciones de estereotipo. Todas las anotaciones de estereotipo se deben colocar en clases abstractas o concretas.
Bigfoot
13

Solía @Component, @Service, @Controllery @Repositorylas anotaciones sólo en las clases de implementación y no en la interfaz. Pero la @Autowiredanotación con Interfaces todavía funcionó para mí.

yalkris
fuente
7

La ventaja de poner anotaciones en @Service es que da una pista de que es un servicio. No sé si alguna clase implementadora heredará esta anotación por defecto.

El lado negativo es que está acoplando su interfaz con un marco específico, es decir, Spring, mediante el uso de anotaciones específicas de Spring. Como se supone que las interfaces deben estar desacopladas de la implementación, no sugeriría usar Anotaciones específicas del marco o parte del objeto de su interfaz.

Kuldeep Tiwari
fuente
1
Creo que todos hemos escuchado el fuerte argumento de acoplamiento varias veces, pero recuerde que las anotaciones pueden estar presentes sin el frasco, por lo que, básicamente, siempre que su acoplamiento esté en las anotaciones, aún se puede desacoplar.
Niels Bech Nielsen
1

Un beneficio de spring es cambiar fácilmente la implementación del Servicio (u otra). Para esto, debe realizar anotaciones en la interfaz y declarar variables como esta:

@Autowired
private MyInterface myVariable;

y no :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

Como en el primer caso, puede activar qué implementación inyectar desde el momento en que es única (solo una clase implementa la interfaz). En el segundo caso, debe refactorizar todo su código (la implementación de la nueva clase tiene otro nombre). Como consecuencia, la anotación debe estar en la interfaz tanto como sea posible. Además, los proxys JDK son adecuados para esto: se crean y crean instancias al inicio de la aplicación porque el tipo de tiempo de ejecución se conoce por adelantado, a diferencia de los proxies CGlib.

François F.
fuente
44
"MyClassImplementationWhichImplementsMyInterface" LOL
inafalcao
No necesita anotar en la interfaz para que el primer ejemplo funcione. Puede realizar anotaciones con @Serviceuna implementación y conectar automáticamente la interfaz. Spring verificará cualquier objeto que implemente esta interfaz.
Marco
1

Pondría @Serviceen su clase, pero puse el nombre de la interfaz como parámetro de la anotación, por ejemplo

interface ServiceOne {}

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

Al hacerlo, obtienes todos los beneficios y aún puedes inyectar la interfaz, pero obtienes la clase

@Autowired 
private ServiceOne serviceOne;

Por lo tanto, su interfaz no está vinculada a Spring Framework y puede cambiar la clase en cualquier momento y no tener que actualizar todos sus puntos de inyección.

Entonces, si quisiera cambiar la clase de implementación, podría simplemente anotar la nueva clase y eliminarla de la primera, pero eso es todo lo que se debe cambiar. Si inyecta la clase, podría tener mucho trabajo cuando quiera cambiar la clase impl.

usuario1239403
fuente
-1

Para hacerlo mas simple:

@Service es una anotación de estereotipo para la capa de servicio .

@Repository es una anotación de estereotipo para la persistencia capa.

@Component es una anotación de estereotipo genérico utilizada para indicarle a Spring que cree una instancia del objeto en el contexto de la aplicación. Es posible definir cualquier nombre para la instancia, el valor predeterminado es el nombre de la clase como caso de camello.

HughParker
fuente
3
No se busca el significado de estas anotaciones, sino DÓNDE ponerlas en la interfaz o su implementación.
nanosoft
-3

Hay 5 anotaciones que podrían usarse para hacer frijoles de primavera. Enumere a continuación las respuestas.

¿Realmente necesitas una interfaz? Si va a tener una implementación para cada interfaz de servicio, simplemente evítela, use solo la clase. Por supuesto, si no tiene RMI o cuando se requiere un proxy de interfaz.

@Repository: utilícelo para inyectar sus clases de capa dao.

@Service: utilícelo para inyectar sus clases de capa de servicio. En la capa de servicio también es posible que deba usar la anotación @Transactional para la gestión de transacciones de db.

@Controller: utilícelo para sus controladores de capa frontend, como los beans administrados por JSF que se inyectan como beans spring.

@RestController: utilícelo para los controladores de reposo de resorte, esto lo ayudaría a evitar cada vez que incluya anotaciones @ResponseBody y @RequestBody en sus métodos de descanso.

@Component: utilícelo en cualquier otro caso cuando necesite inyectar spring bean que no sea controlador, servicio o clase dao

Artur Yolchyan
fuente
Sí, necesita una interfaz en los bordes de sus capas (como la capa de acceso a datos y la capa de servicio). Permiten un acoplamiento flexible de módulos que contienen esas implementaciones de capas. Sin ellos, los clientes de las capas mencionadas tienen que conocer los tipos concretos y debe cambiarlos cuando, por ejemplo, desee decorar su BasicDao con CachingDao ...
Igand