Este documento introduce los conceptos de Context and Dependency Injection (CDI) en Java EE. CDI proporciona un modelo de programación basado en inyección de dependencias y componentes inyectables. Permite la inyección de dependencias, intercepción y decoración de cualquier clase Java que cumpla con los requisitos de un bean gestionado. CDI está construido sobre el principio de acoplamiento flexible y tipado fuerte.
2. Acerca de
Ing. José Amadeo Martin Díaz Díaz
CEO JoeDayz.pe & Docente en EPE UPC
Formación
BlueStar Energy (2007)
Bristol Myers Squibb (2006)
Trans Solutions Systems (2003 - 2005)
Telefonica Servicios Internet (2000 - 2002)
Egresado de la Pontificia Universidad Católica del Perú (1994 - 2000)
@jamdiazdiaz
4. Introducción
La primera versión de Java EE (J2EE) introdujo el
concepto de inversión de control
No fue hasta Java EE 5 y 6 que el API para
administración de ciclo de vida e inyección de
dependencias estuviese robusta.
Hoy CDI nos da un modelo de programación donde
cada componente Java EE puede ser inyectable,
interceptable y administrable.
CDI esta construido sobre la base de “pobre
acoplamiento y fuerte tipado"
6. Entendiendo a los Beans
Java SE tiene JavaBeans
Java EE tiene Enterprise Java Beans
Otros: Servlets, SOAP WS, RESTful WS,
entidades
Beans Manejados
POJOs
7. Entendiendo a los Beans
Los Bean Manejados son objetos administrados
por el contenedor que soportan un conjunto
basico de servicios: inyección de recursos,
administración de ciclo de vida, e intercepción.
Introducidos en Java EE 6
8. Entendiendo a los Beans
Por ejemplo un EJB puede ser un Bean
Manejado con servicios extra
Un Servlet puede ser un Bean Manejado con
servicios extra (diferentes al del EJB), etc. etc.
9. Entendiendo a los Beans
Los Beans son objetos CDI que son
construidos sobre la base del modelo de Bean
Manejados.
Tienen contextos definidos, soporte a inyección
de dependencias, intercepción, decoración,
son especializados con el uso de qualifiers y
pueden ser usados en EL.
10. Entendiendo a los Beans
En resumen, cualquier clase Java que tenga un
constructor por defecto y se ejecute en un
contenedor es un bean.
De esta forma los JavaBeans y EJBs pueden
tomar ventaja de los servicios CDI
12. Dependency Injection
(DI)
Es un patrón de diseño que desacopla
componentes dependientes.
Termino concebido por Martin Fowler.
Java EE 5 introdujo inyección para recursos como
EJBs, entity managers, data sources, fabricas JMS,
y destinos al interior de componentes como
Servlets, JSF beans y EJBs.
Así aparecieron @Resource, @PersistenceContext,
@PersistenceUnit, @EJB y @WebServiceRef
13. Dependency Injection
(DI)
El primer paso tomado en Java EE 5 no fue
suficiente y Java EE 6 creo dos
especificaciones diferentes para potenciar DI en
la plataforma: Dependency Injection (JSR 350) y
Context and Dependency Injection (JSR 299)
En Java EE 7 se han juntado las dos
especificaciones
15. Scopes y Context
CDI viene con scopes predefinidos: request,
session, application y conversation
16. Interception
Similar a la programación orientada a aspectos
(AOP)
El AOP se logra en la plataforma, a través, de
interceptors. Estos son automaticamente
disparados por el contenedor cuando un
método de un bean manejado es invocado.
18. Deployment Descriptor
beans.xml y es obligatorio
Ubicado en META-INF o WEB-INF
Aquí se configura interceptors, decoradores,
alternatives, etc.
Si tu aplicación contiene diferentes jars y
deseas tener CDI para toda la aplicación. Cada
jar debe tener su propio beans.xml
20. Resumen
CDI es importante para otras especificaciones
como Bean Validation, JAX-RS, EJB, JSF.
Pero, CDI 1.1 no sería nada sin otras como: DI
(JSR 330), Managed Bean 1.0 (JSR 342),
Common Annotations 1.2 (JSR 250),
Expression Language 3.0 (JSR 341) e
Interceptors 1.2 (JSR 318)
21. Historia
En el 2006 inspirado en Seam, Guice y Spring
Framework, Gavin King (creador de Seam)
lidero la especificación JSR 299 denominada
Web Beans dirigida para Java EE 6.
Web Beans ha sido renombrado a Context and
Dependency Injection 1.0 construida sobre la
base de la nueva JSR 330 : Dependency
Injection para Java 1.0 (@Inject)
22. Historia
Dependency Injection aporto las anotaciones:
@Inject, @Named, @Qualifier, @Scope,
@Singleton
CDI añadió nuevas características como
context management, events, decorators, e
interceptors (JSR 318). Ademas de permitir al
desarrollador extender la plataforma que era
imposible hasta entonces.
23. Historia
El objetivo principal de CDI es entonces:
Dar mas cohesión a la plataforma
Unir la capa web y la capa de transacciones
Que DI sea el ciudadano de primera clase
Poder agregar nuevas extensiones facilmente
En JAVA EE 7, CDI 1.1 es el fundamento para
multiples JSRs y ha recibido muchas mejoras
24. ¿Que hay de nuevo en
CDI 1.1?
No añade nuevas características. Su objetivo es integrar CDI con
otras especificaciones.
La nueva clase CDI provee acceso programático a facilidades de
CDI fuera de un bean manejado
Interceptors, decoradores, y alternatives pueden ser prioridades
(@Priority) y ordenados para una aplicación completa
Cualquier tipo o paquete puede ser ignorado de ser considerado un
bean para CDI con @Vetoed en el tipo o paquete
El @New qualifier es deprecado y se debe en su lugar usar
@Dependent
@WithAnnotations permite una extensión para filtrar por tipos
26. Implementación de
Referencia
La implementación de referencia para CDI es
Weld, un proyecto Open Source de JBoss
Existen otras como Apache OpenWebBeans o
CanDi (Caucho), así como Apache DeltaSpike
28. Anatomía de un CDI
Bean
No es una clase non-static inner
Es una clase concreta o anotada con
@Decorator y
Tiene un constructor por defecto sin
parámetros, o declara un constructor anotado
con @Inject
Todo lo demás es opcional
33. Puntos de Inyección
El punto de inyección puede ser en propiedad,
setter o constructor
No es necesario crear un getter/setter para un
atributo para usar inyección. No importa si es
privado.
En el caso de un constructor solo puedes tener
uno solo con @Inject
34. Puntos de Inyección
¿Cuándo deberías usar inyección por setter o
constructor?
No hay respuesta técnica real para esta
pregunta; depende de tu elección. Recuerda
que el contenedor es quien hace el trabajo.
35. Default Injection
Si en los ejemplos anteriores asumimos que
GeneradorNumero solo tiene una
implementación (IsbnGenerador). CDI puede
inyectarlo sin problemas usando @Inject
Cuando no declaras un Qualifier, el contenedor
asume el qualifier
@javax.enterprise.inject.Default.
43. Qualifiers con Miembros
Que pasa si queremos tener qualifiers
combinados.
Es decir @DosDigitos, @OchoDigitos,
@DiezDigitos, @TreceDigitos
O @DosParDigitos, @OchoImparDigitos,
@OchoParDigitos, etc.
44. Qualifiers con Miembros
En ese caso podemos crear un solo qualifier
@NumeroDeDigitos con una enumeration como
valor y un Boolean para la paridad.
48. Alternatives
Algunas veces tu deseas inyectar una
implementación según el escenario de
deployment.
Digamos que en el ejemplo que estamos
revisando, deseamos generar un numero falso
(mock) en un ambiente de pruebas.
51. Producers
Hemos visto hasta ahora como un bean CDI se
inyecta en otro bean CDI.
Pero, también podemos inyectar primitivos
(long, float, …), tipos de array, o cualquier otro
POJO que no tiene CDI habilitado. Esto gracias
a los producers.
52. Producers
Por defecto, no podemos inyectar clases de
java.util.Date, java.lang.String. Esto debido a que
estas clases están en rt.jar y este jar no tiene un
beans.xml
Recordemos que si un archivo .jar no tiene
beans.xml bajo un META-INF, CDI no podrá
descubrir nada y el POJO no podrá tratarse como
un bean. Es decir, no podrá ser inyectable.
La única forma de hacerlo inyectable es usando
campos producers o métodos producers.
55. InjectionPoint API
Los atributos y tipos de retorno producidos por
@Produces no necesitan información alguna de
donde ellos serán inyectados
Pero hay otros casos en que si se necesita
saber.
Este último es el caso de
java.util.logging.Logger.
58. Disposers
Hemos usado producers para crear tipos o
POJOs para que sean inyectados. Pero, no
hemos tenido que destruirlos o cerrarlos una
vez usados.
Algunos métodos producers necesitan objetos
que requieren explicitamente destrucción como
JDBC connections, JMS session, o entity
manager.
Para destrucción existen los disposers.
62. Scopes
Los beans con scope @SessionScoped o
@ConversationScoped deben ser serializables,
puesto que el contenedor los pone en pausa
de rato en rato.
Si un scope no es dado. El default es
@Dependent
63. Conversation
Este scope guarda información del estado del
usuario, permanece entre multiples requests y
es demarcado programáticamente por la
aplicación.
Ejemplos de uso: reservas, compras en una
tienda virtual, wizard en general
66. Beans en Expression
Language
Por defecto los beans CDI no tienen un nombre
y no son resuelto vía EL binding.
Para asignarle un nombre se tiene que usar
@Named
68. Interceptors
Los interceptors son de 4 tipos:
@AroundConstruct: Asociado con el
constructor de la clase destino
@AroundInvoke: Asociado con un metodo de
negocio especifico
@AroundTimeout: Solo para EJB timer service
@PostConstruct y @PreDestroy
69. Interceptors
Desde JAVA EE 6, los interceptors han
evolucionado a una especificación separada.
Ellos pueden ser aplicados a Bean Manejados,
así como a EJBs, SOAP y RESTful web services.
71. Interceptor en la misma
clase
Respecto al ejemplo anterior. Solo se intercepta
métodos que sean públicos, privados,
protected o default; pero, no static o final
El método interceptor debe tener un
InvocationContext como parámetro y debe
retornar Object
El método puede arrojar excepciones
chequeadas
72. Interceptor en la misma
clase
Respecto al ejemplo anterior. Solo se intercepta
métodos que sean públicos, privados,
protected o default; pero, no static o final
El método interceptor debe tener un
InvocationContext como parámetro y debe
retornar Object
El método puede arrojar excepciones
chequeadas
75. Interceptor en la misma
clase
En el ejemplo anterior se ha usado
@Transactional. Este se usa para el manejo de
transacciones en CDI beans como Servlets,
JAX-RS, JAX-WS.
@Transactional es implementado via un
interceptor
76. Clases Interceptor
Esta opción es cuando se desea que el
comportamiento cross-cutting concerns se
debe tener en una clase separada.
Un ejemplo de esto es el Logging
79. Clases Interceptor
Si se desea que diferentes métodos sean
interceptados de una clase, se puede colocar la
referencia al interceptor en la parte superior de
la clase.
Y si se desa excluir algún metodo se usara
@ExcludeClassInterceptors
83. Interceptor Binding
Interceptor Binding es solo permitido si CDI es
habilitado
Un Interceptor Binding es una anotación
definida por el usuario con la anotación
@InterceptorBinding
86. Interceptors
Los interceptors esta deshabitados por
defecto. Al igual que las alternatives, los
interceptors tienen que ser definidos en el
beans.xml del jar o módulo Java EE.
88. Priorizando Interceptors
Binding
Si bien los Interceptors binding nos dan pobre
acoplamiento de interceptors, perdemos la
posibilidad de ordenarlos.
Desde CDI 1.1 ya podemos hacerlo usando
@Priority
90. Priorizando Interceptors
Binding
@Priority puede tomar un Integer de cualquier
valor.
La regla es que interceptors con prioridad
pequeña son llamados primero.
Java EE 7 define prioridades a nivel de la
plataforma y podemos tener interceptors
llamados antes o después de ciertos eventos.
91. Priorizando Interceptors
Binding
PLATFORM_BEFORE = 0: Inicio de un rango de interceptors
definidos por la plataforma Java EE
LIBRARY_BEFORE = 1000: Inicio de un rango de interceptors
definidos por extension libraries
APPLICATION = 2000: Inicio de un rango de interceptors
definidos por aplicaciones
LIBRARY_AFTER = 3000: Inicio de un rango de últimos
interceptors definidos por extension libraries
PLATFORM_AFTER = 4000: Inicio de un rango de últimos
interceptors definidos por la plataforma Java EE
92. Priorizando Interceptors
Binding
En Conclusión, si deseamos que nuestro
interceptor sea ejecutado antes de cualquier
interceptor de aplicación, pero después de
cualquier interceptor temprano de la plataforma
debemos escribir:
93. Decoradores
Los decoradores son un patrón de diseño común de
Gang of Four. La idea es tomar una clase y wrap otra
clase alrededor de ella (decorarla).
Es decir, si llamas a una clase decorada, pasamos, a
través, del decorador antes de llegar a la clase destino.
Los Decoradores son especiales para añadir lógica
adicional a un método de negocios.
Son similares a los interceptors en cierta forma, pero
son complementarios
95. Decoradores
Los decoradores deben tener un delegate
injection point anotado con @Delegate, del
mismo tipo que el bean que se esta decorando.
Esto permite al decorador invocar al objeto
delegado y adicionalmente llamar a un método
de negocio de este.
Los decoradores por defecto están
deshabilitados. Estos deben ser habilitados en
el beans.xml
97. Eventos
Los Events permite a los beans interactuar fuera
del tiempo de compilación.
Un Bean puede definir un evento, otro puede
dispararlo y otro manejar el evento
Los beans pueden estar en paquetes separados y
aún en capas separadas de la aplicación
Este es el observer/observable design pattern del
Gang of Four
98. Eventos
Event producers disparan eventos usando la
interface Event. Un producer lanza eventos
llamando al método fire(), pasa el objeto event y no
es dependiente del observer.
En el ejemplo que vamos a ver LibroService
dispara un event (LibroAddedEvent) cada vez que
un Libro es creado.
Este fire(libro) dispara el evento y notifica a los
metodos observer este particular evento.