español - Por qué usar CDI en Java EE
cdi java 8 (4)
El propósito de usar la inyección de dependencia es para que el código que usa lo que se inyecta no tenga una dependencia de fábrica. Con el ejemplo del código de fábrica, hay una llamada al método estático incrustada en el código que no se necesita con el enfoque DI.
Lo que se está inyectando con myFoo
no debería tener que saber sobre la fábrica.
Sé que hay muchos artículos que explican cómo usar CDI en Java EE, pero me cuesta entender qué ventaja aporta. Por ejemplo, supongamos que tengo una clase que actualmente usa una instancia de Foo. Yo también podría hacer
Foo myFoo = new Foo();
o
// Better, FooFactory might return a mock object for testing
Foo myFoo = FooFactory.getFoo();
Sigo leyendo eso con CDI que puedo hacer:
@Inject
Foo myFoo;
pero ¿por qué es esto mejor que el enfoque basado en fábrica anterior? Supongo que hay algún otro caso de uso del que no tengo conocimiento, pero no he podido identificarlo.
Si he entendido las respuestas a continuación, el concepto es que el marco DI actúa como una fábrica maestra de objetos que está configurada centralmente. ¿Es esta una interpretación razonable?
Actualizar
Desde entonces comencé a aprender sobre Spring y ahora tiene mucho más sentido. El siguiente párrafo está tomado de Spring in Practice tomando un ejemplo de una clase AccountService
que, a su vez, usa una instancia de AccountDao
. Me disculpo por la cita larga, pero creo que realmente llega al corazón de por qué los recursos inyectados ofrecen algo más que la inicialización estándar.
Podría haber construido el servicio de cuenta utilizando la nueva palabra clave, pero la creación de objetos de la capa de servicio rara vez es tan sencilla. A menudo dependen de DAO, remitentes de correo, proxies SOAP y otras cosas. Puede instanciar cada una de esas dependencias mediante programación en el constructor de AccountService (o mediante la inicialización estática), pero eso genera dependencias duras y cambios en cascada a medida que se intercambian.
Además, puede crear dependencias externamente y configurarlas en el servicio de cuenta a través de métodos setter o argumentos de constructor. Hacerlo eliminaría las dependencias internas duras (siempre que se declararan en el AccountService por interfaz), pero habría duplicado el código de inicialización en todas partes. Así es como crea un DAO y lo conecta a su AccountService de la manera Spring:
<bean id="accountDao" class="com.springinpractice.ch01.dao.jdbc.JdbcAccountDao"/>
<bean id="accountService"
class="com.springinpractice.ch01.service.AccountService">
<property name="accountDao" ref="accountDao"/>
</bean>
Habiendo configurado los beans como se indicó anteriormente, su programa ahora puede solicitar una instancia de AccountService
desde Spring ApplicationContext y el marco Spring DI se encargará de crear instancias de todo lo que necesite crear instancias.
En un nivel alto, como con la mayoría de las cosas en CompSci, ofrece un nivel de direccionamiento indirecto (o abstracción) que de otro modo estaría codificado en su aplicación como Foo myFoo = new Foo();
. Esa indirección produce un código débilmente acoplado, que hace que las cosas sean modulares, lo que hace que sea más fácil reemplazar, dar servicio, probar clases o subsistemas de una manera más sencilla.
Tenga en cuenta que hay muchos diseños y patrones para la indirección / abstracción: la inyección de dependencia es solo una.
El otro aspecto de tu pregunta es "¿Por qué CDI?" - Bueno, porque alguien ya hizo el trabajo por ti. Siempre puede construir sus propias cosas, pero generalmente es una pérdida de tiempo cuando el objetivo es construir un sistema del mundo real que debe funcionar dentro del presupuesto ya tiempo. ¿Por qué molestarse con las compras y la cocina cuando hay un chef con estrella Michelin que está dispuesto a hacer ese trabajo por usted?
Esta es una pregunta importante y sutil sobre de qué se trata la programación empresarial.
El nombre está bien elegido: contextos y dependencias.
CDI no tiene nada que ver con un código mejor o más limpio, se trata de garantizar que las grandes organizaciones puedan construir sistemas de software complejos y distribuidos y compartir datos. Se trata de estar 100% seguros de que los gobiernos u otras burocracias pueden distribuir indiscriminadamente paquetes independientes y bien documentados para cada pieza de software que controlan. Recuerde que en estos días, prácticamente cualquier POJO se puede inyectar.
Supongamos que está creando una aplicación cliente de algún tipo y desea que imprima el nombre del usuario en la esquina.
A los arquitectos empresariales de esta gran empresa les gustaría que tenga esta capacidad, pero como ingeniero de software junior, no hay ninguna posibilidad de que le entreguen las claves del DB.
También les gustaría proteger los datos en toda la red, pero la compañía no está pagando a ningún ingeniero para rediseñar un cliente de autenticación cada vez que necesitan compartir un trozo de datos.
Les gustaría que puedan consultar y actualizar esta información, pero desearían que las transacciones se manejaran en un nivel superior al de cualquier aplicación.
Les gustaría que puedan probar sus clases con burlas triviales en bloques de configuración.
Quisieran que el acoplamiento entre las clases implique un mínimo de métodos estáticos.
Y sigue y sigue y sigue...
La mayoría de los JSR probablemente tengan un "EA que le gustaría poder ..." enterrado en algún lugar.
Se prefiere CDI porque permite que las aplicaciones de grandes (arbitrarias) escalas horizontales y verticales compartan contextos, dependencias y, por lo tanto, datos.
En palabras de Fowler:
"El problema es cómo puedo hacer ese enlace para que mi clase lister ignore la clase de implementación, pero todavía puede hablar con una instancia para hacer su trabajo".
"Pero si deseamos implementar este sistema de diferentes maneras, necesitamos usar complementos para manejar la interacción con estos servicios, de modo que podamos usar diferentes implementaciones en diferentes implementaciones".
"El enfoque que utilizan estos contenedores es asegurar que cualquier usuario de un complemento siga alguna convención que permita que un módulo ensamblador por separado inyecte la implementación en el lister".
En pocas palabras, permiten un "comando y control" centralizado de aplicaciones empresariales complejas. Java EE es un proceso de abstracción sistematizado y confiable, y CDI es una encarnación que funciona tan bien que casi lo hace invisible. Hace que la costura de aplicaciones complejas sea casi trivial.
Dos cosas más:
Tenga en cuenta que CDI existe pacíficamente junto con el "patrón de localizador de servicios", conocido como JNDI en Java EE, que es preferible si el desarrollador del cliente debe elegir entre muchas alternativas de tipo idéntico.
CDI es más potencia de fuego de lo que se necesita en muchos casos, especialmente casos no empresariales (literalmente).
Las personas que escribieron CDI te dieron una gran fábrica de objetos; hicieron el trabajo por ti, mejor que tú. Se trata de una configuración XML o una anotación controlada, por lo que no es necesario incrustar todo en el código.
Los motores de inyección de dependencia, como Spring, hacen mucho más que su fábrica. Tomará más de una clase de fábrica y una línea de código para duplicar todo lo que ofrecen.
Por supuesto que no tienes que usarlo. Siempre puedes inventar tu propia rueda. Y debería hacerlo, si su propósito es aprender cómo hacer ruedas o eliminar dependencias.
Pero si solo desea desarrollar aplicaciones, es mejor utilizar las herramientas que otros proporcionan cuando le dan una ventaja.
El artículo seminal sobre la inyección de dependencia fue escrito por Martin Fowler. Yo recomendaría leerlo; sigue siendo genial, ocho años después.
"Todavía no está claro en qué más está"
Aquí hay algunas ventajas:
- Acoplamiento más flojo
- Pruebas más fáciles
- Mejor estratificación
- Diseño basado en interfaz
- Proxies dinámicos (segue a AOP).