java - qualifier - dependency annotations{@ org springframework beans factory annotation autowired required true)}
Inyección de Java Dependency: XML o anotaciones (10)
Las anotaciones se están volviendo populares. Spring-3 los apoya. CDI depende mucho de ellos (no puedo usar CDI sin anotaciones, ¿verdad?)
Mi pregunta es por qué ?
Escuché varios problemas:
"Ayuda a deshacerse de XML". Pero, ¿qué tiene de malo xml? Las dependencias son declarativas por naturaleza, y XML es muy bueno para las declaraciones (y muy malo para la programación imperativa). Con un buen IDE (como idea) es muy fácil editar y validar xml, ¿no es así?
"En muchos casos, solo hay una implementación para cada interfaz". ¡Eso no es verdad! Casi todas las interfaces en mi sistema tienen una implementación simulada para las pruebas.
¿Algún otro problema?
Y ahora mis ventajas para XML:
Puede inyectar cualquier cosa en cualquier lugar (no solo el código que tiene anotaciones)
¿Qué debo hacer si tengo varias implementaciones de una interfaz? Usa calificadores? Pero obliga a mi clase a saber qué tipo de inyección necesita. No es bueno para el diseño.
La DI basada en XML aclara mi código: cada clase no tiene idea acerca de la inyección, por lo que puedo configurarla y probarla de alguna manera.
¿Qué piensas?
"¿Pero qué tiene de malo xml?" Es otro archivo para administrar y otro lugar para buscar un error. Si sus anotaciones están justo al lado de su código, es mucho más fácil de gestionar y depurar.
Además, no te olvides de Spring JavaConfig .
Como todas las cosas, la inyección de dependencia se debe usar con moderación. Además, todas las trampas de las inyecciones deben segregarse del código de la aplicación y relegarse al código asociado con main.
En general, las aplicaciones deben tener un límite que separe el código de la aplicación abstracta de los detalles concretos de implementación. Todas las dependencias de código fuente que cruzan ese límite deben apuntar hacia la aplicación. Llamo el lado concreto de ese límite, la partición principal, porque allí es donde debería vivir ''main'' (o su equivalente).
La partición principal consiste en implementaciones de fábrica, implementaciones de estrategia, etc. Y es en este lado de la frontera donde el marco de inyección de dependencias debería hacer su trabajo. Entonces esas dependencias inyectadas pueden pasarse a través del límite a la aplicación por medios normales. (por ejemplo, como argumentos).
El número de dependencias inyectadas debería ser relativamente pequeño. Una docena o menos. En cuyo caso, la decisión entre XML o anotaciones es discutible.
En mi caso, los desarrolladores que escriben la aplicación son diferentes a los que lo configuran (diferentes departamentos, diferentes tecnologías / idiomas) y el último grupo ni siquiera tiene acceso al código fuente (que es el caso en muchas configuraciones empresariales). Eso hace que Guice sea inutilizable, ya que tendría que exponer el código fuente en lugar de consumir los xmls configurados por los desarrolladores que implementan la aplicación.
En general, creo que es importante reconocer que proporcionar los componentes y ensamblar / configurar una aplicación son dos ejercicios diferentes y proporcionar esta separación de preocupaciones si es necesario.
En mi opinión, esto es más una cuestión de gusto.
1) En nuestro proyecto (usando Spring 3), queremos que los archivos de configuración XML sean solo eso: configuración. Si no necesita ser configurado (desde la perspectiva del usuario final) o algún otro problema no lo obliga a hacerlo en xml, no coloque los bean-definitions / wirings en las configuraciones XML, use @Autowired y tal.
2) Con Spring, puede usar @Qualifier para que coincida con una implementación determinada de la interfaz, si existen múltiples. Sí, esto significa que debe nombrar las implementaciones reales, pero no me importa.
En nuestro caso, usar XML para manejar todo el DI hincharía mucho los archivos de configuración XML, aunque podría hacerse en un archivo xml separado (o archivos), por lo que no es ese punto válido;). Como dije, es una cuestión de gustos y creo que es más fácil y más limpio manejar las inyecciones a través de anotaciones (se puede ver qué servicios / repositorios / algo utiliza algo simplemente mirando la clase en lugar de ir a través del archivo XML) buscando la declaración de frijol).
Editar: Aquí hay una opinión sobre @Autowired vs. XML con la que estoy completamente de acuerdo: Spring @Autowired usage
Me gusta mantener mi código claro, como señaló. XML feets mejor, al menos para mí, en el principio de COI.
El principio fundamental de Dependency Injection para la configuración es que los objetos de la aplicación no deberían ser responsables de buscar los recursos o los colaboradores de los que dependen. En su lugar, un contenedor IoC debe configurar los objetos, externalizando la búsqueda de recursos desde el código de la aplicación al contenedor. (Desarrollo J2EE sin EJB - Rod Johnson - página 131)
Una vez más, es solo mi punto de vista, no hay fundamentalismo allí :)
EDITAR: Algunas discusiones útiles por ahí:
Solo puedo hablar por experiencia con Guice, pero esta es mi opinión. A falta de eso, la configuración basada en anotaciones reduce en gran medida la cantidad que tiene que escribir para vincular una aplicación y facilita el cambio de lo que depende de qué ... a menudo sin siquiera tener que tocar los archivos de configuración. Hace esto haciendo que los casos más comunes sean absolutamente triviales a expensas de hacer que ciertos casos relativamente raros sean un poco más difíciles de manejar.
Creo que es un problema ser demasiado dogmático para que las clases "no tengan idea de la inyección". No debe haber ninguna referencia al contenedor de inyección en el código de una clase. estoy completamente de acuerdo con eso. Sin embargo, debemos ser claros en un punto: las anotaciones no son código . Por sí mismos, no cambian nada acerca de cómo se comporta una clase ... aún puede crear una instancia de una clase con anotaciones como si no estuvieran allí en absoluto. Así que puedes dejar de usar completamente un contenedor DI y dejar las anotaciones allí y no habrá ningún problema.
Cuando elige no proporcionar pistas de metadatos sobre la inyección dentro de una clase (es decir, anotaciones), está desperdiciando una valiosa fuente de información sobre las dependencias que requiere esa clase. Te obligan a repetir esa información en otro lugar (en XML, por ejemplo) o a confiar en la magia no confiable como el autoenrutamiento, lo que puede generar problemas inesperados.
Para abordar algunas de sus preguntas específicas:
Ayuda a deshacerse de XML
Muchas cosas son malas acerca de la configuración XML.
- Es terriblemente detallado.
- No es seguro para tipos sin herramientas especiales.
- Obliga el uso de identificadores de cadena. De nuevo, no es seguro sin el soporte de herramientas especiales.
- No toma ninguna ventaja de las características del lenguaje, lo que requiere todo tipo de construcciones feas para hacer lo que podría hacerse con un método simple en el código.
Dicho esto, sé que mucha gente ha estado utilizando XML por el tiempo suficiente como para estar convencidos de que está bien y realmente no espero cambiar de opinión.
En muchos casos, solo hay una implementación para cada interfaz
A menudo, solo hay una implementación de cada interfaz para una sola configuración de una aplicación (por ejemplo, producción). El punto es que al iniciar su aplicación, normalmente solo necesita vincular una interfaz a una sola implementación. Puede ser utilizado en muchos otros componentes. Con la configuración XML, debe decirle a cada componente que usa esa interfaz que use este enlace particular de esa interfaz (o "bean" si lo desea). Con la configuración basada en anotaciones, solo declara el enlace una vez y todo lo demás se soluciona automáticamente. Esto es muy significativo y reduce drásticamente la cantidad de configuración que tiene que escribir. También significa que cuando agrega una nueva dependencia a un componente, ¡a menudo no tiene que cambiar nada en absoluto sobre su configuración!
Que tengas implementaciones simuladas de alguna interfaz es irrelevante. En pruebas unitarias, normalmente solo creas el simulacro y lo pasas en ti ... no está relacionado con la configuración. Si configura un sistema completo para pruebas de integración con ciertas interfaces utilizando simulaciones en su lugar ... eso no cambia nada. Para la ejecución de la prueba de integración del sistema, todavía solo está utilizando 1 implementación y solo debe configurar esa vez.
XML: puedes inyectar cualquier cosa en cualquier lugar
Puedes hacerlo fácilmente en Guice y me imagino que también puedes hacerlo en CDI. Por lo tanto, no es absolutamente imposible que lo haga mediante el uso de un sistema de configuración basado en anotaciones. Dicho esto, me atrevería a decir que la mayoría de las clases inyectadas en la mayoría de las aplicaciones son clases en las que puedes agregar un @Inject
si no está ya allí. La existencia de una biblioteca ligera estándar de Java para anotaciones (JSR-330) hace que sea aún más fácil para más bibliotecas y marcos proporcionar componentes con un constructor anotado @Inject
en el futuro.
Más de una implementación de una interfaz
Los calificadores son una solución para esto, y en la mayoría de los casos deberían estar bien. Sin embargo, en algunos casos desea hacer algo donde no funcione el uso de un calificador en un parámetro en una clase inyectada en particular ... a menudo porque quiere tener varias instancias de esa clase, cada una usando una implementación o instancia de interfaz diferente. Guice resuelve esto con algo llamado PrivateModule
s. No sé qué ofrece CDI a este respecto. Pero, de nuevo, este es un caso que está en minoría y no vale la pena que el resto de su configuración sufra por ello mientras pueda manejarlo.
Solo tengo un par de cosas para agregar a lo que ya está aquí.
Para mí, la configuración DI es código. Me gustaría tratarlo como tal, pero la naturaleza misma de XML evita esto sin herramientas adicionales.
Spring JavaConfig es un importante paso adelante en este sentido, pero todavía tiene complicaciones. El escaneo de componentes, la selección auto-mágica de implementaciones de interfaz y la semántica en torno a la intercepción de CGLIB de las clases con anotación de @Configuration lo hacen más complejo de lo que debe ser. Pero todavía es un paso adelante de XML.
El beneficio de separar los metadatos de la IoC de los objetos de la aplicación es exagerado, especialmente con Spring. Quizás si se limitara solo al contenedor Spring IoC, esto sería cierto. Pero Spring ofrece una amplia pila de aplicaciones construida en el contenedor IoC (Security, Web MVC, etc.). Tan pronto como aproveches algo de eso, estarás atado al contenedor de todos modos.
Tengo el siguiente principio: los beans relacionados con la configuración se definen con XML. Todo lo demás - con anotaciones.
¿Por qué? Porque no quieres cambiar la configuración en las clases. Por otro lado, es mucho más simple escribir @Service
y @Inject
, en la clase que desea habilitar.
Esto no interfiere con las pruebas de ninguna manera; las anotaciones son solo metadatos que analiza el contenedor. Si lo desea, puede establecer dependencias diferentes.
En cuanto a CDI, tiene una extensión para la configuración XML, pero tienes razón, usa principalmente anotaciones. Sin embargo, eso es algo que no me gusta especialmente.
XML tiene el único beneficio de un estilo declarativo que se define claramente separado del código de la aplicación en sí. Eso se mantiene independiente de las preocupaciones de DI. Las desventajas son la verbosidad, la poca robustez de factorización y un comportamiento de falla de tiempo de ejecución general. Existe solo un soporte de herramienta general (XML) con poco beneficio en comparación con el soporte IDE para, por ejemplo, Java. Además, este XML viene con una sobrecarga de rendimiento, por lo que generalmente es más lento que las soluciones de código.
Frecuentemente se dice que las anulaciones son más intuitivas y robustas al volver a factorizar el código de la aplicación. También se benefician de una mejor orientación IDE como proporciona Guice. Pero mezclan el código de la aplicación con las preocupaciones de DI. Una aplicación se vuelve dependiente de un marco. La separación clara es casi imposible. Las anotaciones también son limitadas cuando se describen comportamientos de inyección diferentes en el mismo lugar (constructor, campo) dependiendo de otras circunstancias (por ejemplo, problema con las patas del robot). Además, no permiten tratar clases externas (código de biblioteca) como su propia fuente. Por lo tanto, se considera que se ejecutan más rápido que XML.
Ambas técnicas tienen serias desventajas. Por lo tanto , recomiendo usar Silk DI . Es declarativo definido en el código (gran soporte IDE) pero está 100% separado del código de su aplicación (sin dependencia del marco). Permite tratar todo el código igual sin importar si es de su fuente o una biblioteca externa. Problemas como el problema de las piernas del robot son fáciles de resolver con los enlaces habituales. Además, tiene un buen soporte para adaptarlo a sus necesidades.