Tema 5. Capa de l´
ogica de aplicaci´
on en
Java EE
DAGSS – Dise˜
no de Arquitecturas de Grandes Sistemas Software
4
oGrado Ing. Inform´
atica
http://ccia.ei.uvigo.es/docencia/DAGSS
5.1 Enterprise JavaBeans, versi´
on 3.x
Componentes del lado del servidor que encapsulan la l´
ogica de la
aplicaci´
on y que son gestionados por el contenedor de EJBs
Cada Enterprise JavaBean encapsula parte de la l´
ogica de negocio
de la aplicaci´
on
Paquete
javax.ejb.*
: interfaces, anotaciones, excepciones, ...
Ventajas que aportan
Permiten la distribuci´
on de la l´
ogica entre distintas m´
aquinas
man-teniendo la transparencia
• Uso de directorios JNDI para nombrar y acceder a los componentes y recursos
Manejo de transacciones para controlar accesos concurrentes
asegu-rando la integridad de los datos
• Controladas por el contenedor de EJB
Simplifican el desarrollo de aplicaciones que atiendan una gran
varie-dad de clientes (clientes web o ”de escritorio” (
stand-alone
), cliente
locales o remotos, etc)
Dise˜
no orientado a componentes
→
reusabilidad y abstracci´
on
• El desarrollador se concentra en la l´ogica de negocio y utiliza los servicios proporcionados por el contenedor
Servicios b´
asicos a los que da soporte el contenedor EJB
1. Persistencia mediante JPA (
Java Persistence API
)
2. Invocaci´
on remota de m´
etodos mediante RMI/IIOP
3. Procesamiento de transacciones y control de la concurrencia
Por defecto cada invocaci´on de un m´etodo de un EJB forma parte de una transacci´on
4. Procesamiento de eventos/mesajes as´ıncronos
(API Java Message Service[JMS])
5. Servicios de directorio:
JNDI (Java Naming and Directory Interface)6. Seguridad: autenticaci´
on, control de acceso y privilegios, criptograf´ıa
7. Publicaci´
on de los m´
etodos de negocio de los EJBs como servicios
Web SOAP (JAX-WS) o REST (JAX-RS)
(a) Tipos de EJB
Message-Driven EJBs
(EJBs dirigidos por mensajes)
Permiten el procesamiento de mensajes (operaciones) de forma
as´ıncrona (recepci´
on y tratamiento de eventos JMS)
Act´
uan como
listeners
(escuchadores) de eventos JMS (
Java
Message Service
)
• Implementan el interfaz MessageListener
Se ”suscriben” a una cola (
queue
) quedando a la espera y se
activan cuando se recibe un mensaje dirigido a dicha cola
• Esos mensajes JMS pueden ser enviados por cualquier componente de una aplicaci´on Java EE (clientes, componentes Web, otros EJBs)
• Los ”clientes” de un Message-Driven EJB no invocan directamente sus m´etodos, simplemente env´ıan mensajes JMS
Session EJBs
(EJBs de sesi´
on)
Representan
procesos de negocio
(funcionalidades de la aplicaci´
on)
⇒
implementan un
interfaz de negocio
(
bussines interface
)
Gestionan la interacci´
on con los ”clientes” (objetos/procesos que
hacen uso del componente) y encapsulan el flujo y manipulaci´
on
de la informaci´
on en el servidor
• Proporcionan a los ”clientes” una ”fachada” de los servicios proporcionados por otros componentes disponibles en el servidor (patr´on de dise˜no Facade)
Ofrecen operaciones s´ıncronas (petici´
on-respuesta)
• Procesos de negocio ejecutados en respuesta a una solicitud del cliente
Contenedor de EJBs crea e inicializa sus instancias (inyect´
andoles
las referencias necesarias) y las asigna a los ”clientes” a medida
que estos los van requiriendo (
pool
de EJBs)
En un instante de tiempo dado, s´
olo un ”cliente” tiene acceso a
los m´
etodos de la instancia del EJB (control de concurrencia)
• Contenedor de EJBs garantiza que cada m´etodo del EJB se ejecuta dentrode una transacci´on at´omica
Nota:Desde EJB 3.1 se permite declarar m´etodos as´ıncronos dentro de EJBs de sesi´on marc´andolos con la anotaci´on @Asyncronous
En el caso de que el m´etodo tenga valor de retorno T, el tipo del valor de retorno del m´etodo as´ıncrono ser´a Future<T>
public Future<EstadoPago> procesarPagoTarjeta(int cantidad, Tarjeta tarjeta){...}
(b) EJBs de sesi´
on
Tipos de EJB de sesi´
on:
en funci´
on la interacci´
on con el ”cliente”
(quien realiza las llamadas)
Stateful EJB: tienen un estado conversacional dependiente del cliente
• Cada llamada est´a condicionada por las anteriores (importa el orden)
• Los valores de sus atributos se mantienen entre las distintas invocaciones de un mismo ”cliente”
◦ Representan el estado de la interacci´on con un cliente espec´ıfico
• Cada instancia de un stateful EJB ”atiende” invocaciones de un ´unico ”cliente”
◦ En funci´on delestado conversacional el resultado de las operaciones realizadas podr´a variar
• Estado conversacional no es persistente (no se mantiene cuando el cliente ”libera” el EJB)
◦ Valores de atributos no premanentes: finalizada sesi´on el estado desaparece
◦ Por eficiencia el contenedor de EJBs puede decidir detener temporalmente la ejecuci´on un
stateful EJB, almacenando temporalmente su estado en disco para recuperarlo al volver a la ejecuci´on
• Ejemplo: objeto”carrito de la compra” en el cual se van a˜nadiendo productos
Stateless EJB: no almacenan datos de los ”clientes” que los invocan
• Cada llamada es independiente de las dem´as
• Para el ”cliente” todos los stateless EJB son id´enticos (e intercambiables)
◦ Estado de unstateless EJB no contiene informaci´on espec´ıfica de un cliente
no se garantiza que los valores de sus atributos se mantengan entre llamadas
◦ Stateless EJBs realizan tareas gen´ericas e id´enticas para todos los clientes
• Pueden implementar Servicios Web (anotaciones @WebServicey @WebMethod)
• Ejemplo: objeto”gestor de art´ıculos”: altas, bajas, modificaciones de art´ıculos
Singleton EJB: contenedor garantiza que existe una ´unica instancia del objeto, compartida por todos los ”clientes” del EJB (estado global compartido).
• Por defecto el acceso concurrente lo gestiona el contenedor, pero puede controlarse por c´odigo mediante anotaciones @Lock
• Uso t´ıpico: gesti´on de datos globales de la aplicaci´on (cach´es, etc)
Interfaces en EJB de sesi´
on
Interfaz de negocio
de un EJB define el tipo de acceso permitido a
sus clientes
(Define la visi´on del EJB que tiene el cliente)Un EJB de de sesi´
on puede tener varios interfaces de negocio con
distintos tipos de acceso
Clientes remotos: pueden ejecutarse en m´aquinas virtuales (JVM) distintas a la del EJB que invocan
• Pueden ser: componentes web (servlet, JSP), clientes remotos u otros EJBs
• Para el cliente remoto la localizaci´on del EJB es transparente (s´olo necesita acceso al directorio JNDI)
(c) Definici´
on de EJBs de sesi´
on
(1) Definici´
on del interfaz de negocio
•
Interfaces de negocio
→
interfaces Java decorados con las
anota-ciones
@Remote
o
@Local
para indicar las restricciones de acceso
◦ El interfaz y todos los m´etodos definidos deben de ser public
◦ Mismas restriciones para tipos de par´ametros y valores de retorno que Java RMI
•
Si no se indica con una anotaci´
on en el interfaz o en el EJB se
asume todos los interfaces son locales por defecto
•
Ejemplos:
@Remote
public interface CarritoCompra {
public void inicializarCarrito(Cliente c);
public void anadirArticulo(Articulo a, int cant); public void eliminarArticulo(Articulo a);
public void vaciarCarrito(); };
@Local
public interface GestorClientes { public void alta(Cliente c); public void baja(Cliente c); public void actualizar(Cliente c; public cliente buscarDNI(String DNI); };
•
Nota:
Llamadas remotas son mucho m´
as costosas que locales
◦ En general se tiende a pasar par´ametros ”grandes” ⇒ reducir n´um. dellamadas pasando mayor cantidad de informaci´on
(2) Implementaci´
on de EJBs de sesi´
on
•
Clases
de
implementaci´
on
marcadas
con
las
anotaciones
@Stateless
,
@Stateful
´
o
@Singleton
seg´
un del tipo de
bean
•
Se indican los interfaces de negocio implementados (
implements
)
@Statelesspublic class GestorClientesBean implements GestorClientes { ... } @Stateful
public class CarritoCompraBean implements CarritoCompra { ... }
◦ Opcionalmente se puede asociar un nombre JDNI al EJB para su acceso (par´ametro mappedName="...." de ambas anotaciones)
@Stateless(mappedName="gestor_clientes") ... @Stateful(mappedName="carrito_compra") ...
Nota: si no se indica nada el contendor EJB asignar´a uno por defecto
◦ Opcionalmente se puede omitir la palabra clave implements explicitando el nombre y el tipo de acceso de los interfaces de negocio soportados mediante anotaciones.
@Stateless @Local(GestorClientes.class) ... @Stateful @Remote(CarritoCompra.class) ...
◦ En EJB 3.1 (incluido EJB lite), no se requiere definir interfaz para EJBs
con acceso local (no-inteface view), basta marcar la clase con la anotaci´on
•
Se pueden marcar m´
etodos con anotaciones especiales para
in-dicar que sean invocados por el contenedor EJBs en momentos
concretos del ciclo de vida del
bean
◦ @PostConstruct: una vez que el contenedor instancia el EJB y le inyecta dependencias (antes de recibir su primera invocaci´on)
◦ @PreDestroy: justo antes de eliminar definitivamente el EJB
◦ @PrePassitivate: (s´olostateful) justo antes almacenar el estado en disco temporalmente
◦ @PostPassitivate (s´olo stateful) justo de recuperar el estado almacenado en disco temporalmente
•
M´
etodo anotado con
@Remove
puede ser invocado por clientes para
provocar eliminaci´
on de una instancia del EJB del contenedor
(3) Empaquetado y despliegue
•
Empaquetado de EJBs:
Creaci´
on de fichero JAR conteniendo:
◦ Bytecode (ficheros .class) de
clases de implemementaci´on de EJBs interfaces de negocio
otras clases auxiliares necesarias
Ficheros .class estructurados en paquetes (subdirectorios) seg´un corresponda
◦ Directorio META-INF conteniendo los ficheros de configuraci´on exigidos por el contenedor o/y otros que pudieran ser necesarios
descriptor de despliegue [ejb-jar.xml]
descriptor de persistencia JPA [persistence.xml]
MANIFEST.MF
otros: descriptor de despliegue espec´ıfico del contenedor (glassfish-ejb-jar.xml) ...
◦ Librer´ıas adicionales (ficheros JAR)
•
Despliegue de EJBs:
El fichero JAR resultante se puede
des-plegar directamente en el contenedor JEE o incluirlo como un
m´
odudo EJB de una Aplicaci´
on JEE (paquetes
EAR
)
◦ Al ser deplegado un EJB en un contenedor se le asocia un nombre seg´un lo indicado en sus anotaciones o en su descriptor de despliegue
◦ Ese nombre se registra en el servidor de nombres del contendor EJB, accesible por JNDI.
◦ Una vez desplegado los clientes pueden acceder al EJB usando ese nombre e invocar sus m´etodos
(c) Acceso e invocaci´
on de EJBs de sesi´
on
Para utilizar m´
etodos de un EJB desplegado es necesario que el
cliente cuente con una referencia a un representante (
proxy
o
stub
)
del mismo
• proxy gestiona las invocaciones, bien locales o bien sobre RMI/IIOP
Opci´
on 1:
Inyecci´
on de dependencias por parte del contenedor JEE
•
Uso de la anotaci´
on
@EJB
acompa˜
nando al atributo donde se
mantendr´
a la referencia al EJB
◦ El tipo del atributo/referencia ser´a el nombre del interfaz de negocio que se desea invocar
◦ El contenedor usar´a el nombre por defecto del EJB (o el que se especifique en el par´ametro @EBJ(mappedName="...")) para consultar al servidor de nombres JNDI, inyectando en ese atributo la referencia encontrada
•
Inyecci´
on de referencias con
@EJB
s´
olo es posible dentro de un
entorno de ejecuci´
on JEE
◦ Contenedor de servlets: es posible inyectar EJBs para invocarlos desde servlets, p´aginas JSP, Java beans o @ManagedBeans de JSF
◦ Contenedor de EJBs: posible inyectar EJBs para invocarlos desde otros EJBs
◦ Contenedor de clientes JEE: clientes Java stand-alone ejecut´andose en el contexto de un contenedor de clientes JEE pueden obtener e invocar EJBs
Es necesario disponer de las API de JEE 6 para inyectar estas dependencias
Ejemplo: appclient en GlassFish
Importante:Los contenedores de clientes JEE s´olo pueden inyectar EJBs sobre atributos de tipo static de la clase principal donde se incluya el m´etodo main()
•
Ejemplo:
public class ClaseLlamadora {
@EJB // puede especificarse un nombre de EJB con mappedName (opcional) private CarritoCompra carrito;
...
public void metodoLlamador(String args[]) { ... carrito.inicializar(...); carrito.anadir(...); ... } }
Opci´
on 2:
Consulta JDNI empleando el nombre asignado al EJB
•
Siempre es posible consultar el servicio JNDI presente en todos
los servidores aplicaciones JEE
◦ Se usa el API de JNDI → paquete javax.naming.*
◦ Interfaz InitialContext, m´etodos lookup(...)
•
Se obtiene una referencia a un EJB a partir del nombre asignado
(en la anotaci´
on, en el descriptor de despliegue o del nombre por
defecto asignado por el contenedor)
◦ Este era el modo en que se hac´ıa en las versiones de EJB 2.x y anteriores
◦ Antes de JEE 6: el nombre por defecto con el que se registraban los EJBs no estaba estandarizado
cada servidor de aplicaciones organizaba el directorio de nombres JNDI de forma distinta
◦ JEE 6 especifica formato estandar para nombres por defecto de los EJBs
java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>]
•
Consultas JNDI desde clientes
stand-alone
◦ Es necesario configurar las properties de la m´aquina virtual cliente para indicar la direcci´on y el puerto de escucha del servicio JNDI del contenedor donde est´a desplegado el EJB (dependiente de cada contenedor)
Nota: con GlassFish las propiedades a especificar son:
org.omg.CORBA.ORBInitialHost →IP/nombre servidor aplicaciones JEE
org.omg.CORBA.ORBInitialPort →3700
Pueden indicarse como par´ametros de la JVM al arrancar (-Dparametro=valor) o con System.setProperty(’’parametro’’, valor);
◦ Con esa informaci´on ser´a posible obtener un InitialContex donde buscar [lookup()] el nombre del EJB deseado
•
Ejemplo:
import javax.naming.InitialContext; public class EjemploCliente {
public static void main(String args[]) { ...
InitialContext ic = new InitialContext(); CarritoCompra carrito = (CarritoCompra) ic.lookup("java:global/EjemploTiendaWeb/"+ "EjemploTiendaWeb-ejb/CarritoCompraBean"); carrito.inicializar(...); carrito.anadir(...); ... }
Transacciones en EJBs
Contenedor de EJBs ofrece por defecto gesti´
on de transacciones sobre
m´
etodos de EJBs
(container-managed transactions [CMT])EJB tambi´
en pueden gestionar desde c´
odigo sus propias transacciones
(
bean managed transactions [BMT]
)
Mediante el API JTA (Jave Transaction API) [objetosjavax.transaction.UserTransaction]
UserTransaction provee los m´etodos begin() , commit() y rollback()
EJBs con transacciones BMT se ”marcan” con la anotaci´on
@@TransactionManagement(TransactionManagementType.BEAN)
Se puede especificar que el contenedor de EJBs inyecte una instancia de
UserTransaction mediante la anotaci´on @Resource @Resource
UserTransaction utx;
Tambi´en se pueden obtener con un consulta JNDI
En la gesti´
on de transacciones se busca garantizar las propiedades ACID:
Atomicidad (Atomicity): una transacci´on est´a compuesta de 1 o m´as unidades de trabajo
• o se ejecutan TODAS ellas [commit]
• o no se ejecuta NINGUNA [rollback], si ocurre alg´un error (exception) inesperado no recuperable
Consistencia (Consistence): al finalizar la transacci´on (´exito [commit] ´o fracaso [rollback]) los datos se dejan en un estado consistente
aIslamiento (Isolation): el estado intermedio de la transacci´on no es visible a los dem´as compo-nentes de la aplicaci´on (u a otras aplicaciones)
Durabilidad (Durability): una vez la transacci´on se completa con ´extio [commit] los cambios realizados sobre los datos son visibles al resto de aplicaciones
Por defecto todos los m´
etodos de los EJBs que usan CBT se ejecutar´
an
dentro de una transacci´
on (no es necesaria configuraci´
on expl´ıcita)
EJBs se consideran anotados por defecto con@TransactionManagement(TransactionManagementType.CONTAINER)
Pueden especificarse caracter´ısticas espec´ıficas en la gesti´on de transacciones a nivel de EJB o de m´etodo [anotaci´on @TransactionAttribute(TransactionAttributeType.XXX)]
• Si el ”cliente” del EJB ya ha iniciado una transacci´on, el m´etodo del EJB se ejecuta formando parte de ella.
• En otro caso, se inicia una transacci´on nueva para el m´etodo del EJB.
(el m´etodo del EJB se ejecuta siempre dentro de una transacci´on, propia o heredada) TransactionAttributeType.REQUIRES NEW
• Se inicia siempre una nueva transacci´on para el EJB.
• Si el ”cliente” ya hab´ıa iniciado una transacci´on, esta se suspende y se reanuda cuando termine el m´etodo del EJB.
(el m´etodo del EJB se ejecuta siempre dentro de una transacci´on propia) TransactionAttributeType.SUPPORTS
• Si el ”cliente” ha iniciado una transacci´on, el m´etodo del EJB se ejecuta dentro de ella.
• En otro caso, se ejecuta el m´etodo del EJB sin iniciar una transacci´on nueva. (se mantiene el estado transaccional del ”cliente”)
TransactionAttributeType.MANDATORY:
• Si el ”cliente” no ha iniciado una transacci´on, se lanza una excepci´on y se aborta la ejecuci´on del m´etodo del EJB.
• En otro caso, se utiliza la transacci´on iniciada por el ”cliente”.
(el m´etodo del EJB se ejecuta siempre dentro de una transacci´on proporcionada por el ”cliente”) TransactionAttributeType.NOT SUPPORTED
• Si el ”cliente” ha iniciado una transacci´on, esta se suspende, se ejecuta el m´etodo del EJB sin iniciar una transacci´on nueva y se reanuda la transacci´on del cliente.
(el m´etodo del EJB se ejecuta fuera de cualquier transacci´on) TransactionAttributeType.NEVER:
• Si el ”cliente” ha iniciado una transacci´on, se lanza una excepci´on y esta se suspende y no se ejecuta el m´etodo.
5.2 CDI: Context and Dependece Injection
Framework de inyecci´
on de dependencias y gesti´
on de objetos, disponible
desde Java EE 6.
Simplifica el desarrollo de componentes Java EE haciendo uso del principio IoC Inversion of Control
Servicios ofrecidos por CDI
1.
Inyecci´
on de dependencias: inyecci´
on de referencias a objetos
”fuertemente tipada”
Favorece un bajo acoplamiento
• simplifica plantear un dise˜no donde se depende de abstracciones (interfaces) en lugar de depende de implementaciones concretas
• CDI ”carga” con la responsabilidad de la creaci´on de los objetos
• no es necesario especificar las clases concretas a utilizar ni sus respectivas dependencias, CDI crear´a los objetos ”correctos” e inyectar´a esas referencias Posibilidad de ”configurar” la inyecci´on concreta en tiempo de despliegue (descriptor beans.xml)
2. Gesti´
on de
contextos: ciclo de vida de los objetos CDI est´
a vinculado
a contextos (
scopes
)
3. Gesti´
on del
ciclo de vida
de los objetos CDI (
beans CDI
): uso de
interceptores de llamadas a m´
etodos, definici´
on de decoradores y
gesti´
on de eventos
4.
Nombrado
de los
beans
: permite el acceso a los
beans
CDI desde
el
Expression Language
(EL) de JSF y JSP
(simplifica la integraci´on de la capa web y de la capa de l´ogica de aplicaci´on)Beans CDI: un
bean
CDI puede ser casi cualquier objeto Java
No exige implementar interfaces concretos o heredar de determinadas clases : POJOs [plain old Java objects]
Puede ser accedido desde objetos ”cliente” v´ıa inyecci´on de dependencias (@Inject) o mediante un nombre desde el EL de JSF y JSP.
Componentes Java susceptibles de ser gestionados por CDI deben verificar: 1. no son una clase interna no est´atica
2. son una clase concreta o est´a anotada con @Decorator
3. tienen un constructor sin par´ametros o uno de sus constructores est´a anotado con @Inject
A un bean CDI puede vincul´arsele:
1. un contexto (scope) [@ApplicationScoped, @SessionScoped, @RequestScoped, ...] 2. un nombre EL [Named]
3. un conjunto de cualificadores [@Qualifier] que delimitan el tipo de cliente que podr´a inyectarlos
4. un conjunto de interceptores de m´etodos [@ArroundInvoke, @ArroundConstructor, @Interceptors]
5. puntos de gesti´on del ciclo de vida [@PostConstruct, @PreDestroy] 6. un conjunto de decoradores [@Decorator, @Delegate]
7. un conjunto de ”observadores” de eventos [Event<T>, @Observes]
Por defecto, se habilita CDI incluyendo un descriptor de despliegue beans.xml vac´ıo con la opci´onbean-discovery-mode="annotated"en los directorios de configuraci´on de la aplicaci´on (WEB-INF en aplicaciones web, META-INF en el resto de casos)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="annotated"> </beans>
Framework CDI considera susceptibles de ser tipos v´alidos para los beans CDI todos los interfaces, clases abstractas, clases concretas, arrays y tipos b´asicos incluidos en la aplicaci´on, excepto los paquetes o tipos marcados con la anotaci´on
(a) Inyecci´
on de dependencias
Inyecci´
on de dependencias (DI :
dependence injection
) es un principio
de dise˜
no que desacopla la creaci´
on de objetos dependientes
la responsabilidad de crear los objetos y obtener las dependencias
necesarias pasa al contenedor de DI
(ejemplos: Spring, Google Guice, CDI)en
Java
EE,
DI
presente
en
distintas
especificaciones:
@ManagedBeans
en JSF,
@EJB
,
@PersistenceContext
en EJBs,
inyecci´
on de recursos con
@Resource
(CDI unifica todas esas especifica-ciones)Anotaci´
on
@Inject
Define en el objeto ”cliente”
(quien recibe la referencia de la dependencia inyectada)un punto de inyecci´
on de una referencia a un bean CDI del
tipo especificado
(con frecuencia un nombre de interfaz Java)Puede estar acompa˜
nado de uno o m´
as cualificadores
• usados en el caso de tipos de objetos CDI con varias implementaciones para delimitar la que finalmente ser´a inyectada
Puede especificarse un punto de inyecci´
on:
• en el propio atributo de la clase del bean CDI donde se inyectar´a la dependencia @Inject TipoBean atributo;
• en el m´etodo set() de ese atributo
@Inject void setAtributo(TipoBean atributo) { this.atributo = atributo;
}
• en un constructor
@Inject public ClaseBean(TipoAtributo atributo) { this.atributo = atributo;
Cualificadores
Por defecto CDI asume que existe una ´
unica implementaci´
on del tipo de
bean especificado por
@Inject
.
En caso de que s´
olo exista una implementaci´
on se inyecta la
corres-pondiente referencia
(creando e inicializando el bean CDI si es necesario)• Por defecto todos los beans CDI cuantan con el cualificador Default
• La anotaci´on @Inject impl´ıcitamente
En caso de que existan m´
as implementaciones los cualificadores
(
@Qualifier
) permiten seleccionar cu´
al inyectar en cada caso
Las distintas implementaciones de un tipo CDI pueden estar
vin-culadas con anotaciones que ”hereden” de la anotaci´
on
Qualifier
(pueden vincularse a una clase varios cualificadores y ”exigirse” varios cualificadores en los @Inject)@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD}) public @interface Calificador1 { }
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD}) public @interface Calificador2 {
int parametro(); Tipo tipo(); }
public enum Tipo {A,B,C} public interface TipoBean; @Default
public class Implementacion1 implements TipoBean {...} @Calificador1
public class Implementacion2 implements TipoBean {...} @Calificador2(parametro=25, tio=Tipo.A)
public class ClienteBasico { ...
@Inject @Calificador1 TipoBean inyectado; ...
}
public class ClienteMejorado { ...
@Inject @Calificador2(parametro=25) TipoBean inyectado; ...
}
Si existen varias implementaciones, una de ellas debe estar marcada
con el cualificador
@Default
(si no es as´ı se genera una excepci´on)• Por defecto todos los beans CDI que no incluyan un cualificador se anotan con el cualificador Default
• Si no se especifican cualificadores acompa˜nando a una anotaci´on @Inject, impl´ıcitamente se ”exige” Default
En el fichero
beans.xml
se puede modificar en tiempo de despliegue
el comportamiento por defecto, seleccionando un cualificador por
defecto de entre los marcados con
@Alternative
@Alternative @Default
public class Implementacion1 implements TipoBean {...} @Alternative @Calificador1
public class Implementacion2 implements TipoBean {...} ... <beans ...> <alternatives> <class>paquete.Implementacion2</class> </alternatives> </beans>
Por defecto las alternativas est´
an deshabilitadas, deben indicarse
expl´ıcitamente en
beans.xml
Productores
(anotaci´
on
@Produces
)
Usando la anotaci´
on
@Produces
es posible especificar que el origen de
una dependencia a inyectar sea el resultado de la invocaci´
on de un
m´
etodo en lugar de ser un objeto de una clase determinada
(tambi´en es posible vincular @Produces a los atributos de una clase)El m´etodo anotado con @Produces podr´a ir acompa˜nado de los cualificadores que correspondan.
En caso de que no exista una clase adecuada para la inyecci´on (o se haya especificado as´ı en beans.xml), el contenedor CDI se encargar´a de buscar un m´etodo adecuado para la inyecci´on entre los paquetes y clases de la aplicaci´on. Si lo encuentra, CDI lo invocar´a (creando una instancia si es necesario) e inyectar´a su valor de retorno en el punto/s de inyecci´on marcado por @Inject
La anotaci´on @Produces permite inyectar arrays y tipos b´asicos
Cuando existen cualificadores y alternativas los m´etodos @Produces funcionan como una especie de m´etodos factor´ıa ”tipado”, gobernado por los cualificadores, el beans.xml y la propia l´ogica del m´etodo.
En los casos en que la l´ogica del m´etodo @Produces requiera informaci´on sobre el contexto donde se va a inyectar su resultado puede incluir como par´ametro adicional un objeto InjectionPoint con informaci´on del ”cliente” CDI.
public class Productor {
@Produces @Calificador2(parametro=25) TipoBean productor1() { TipoBean instancia;
...
return instancia; }
@Produces @Calificador1 TipoBean productor1(InjectionPoint ip) { TipoBean instancia;
...
String claseReceptora = ip.getMember().getDeclaringClass().getName(); ...
return instancia; }
(b) Contextos (scopes) en CDI
Los beans CDI ”viven” en un contexto (alcance) gestionado por el
contendor CDI
Contenedor crea y maneja los beans dentro de cada contexto,
des-truy´
endolos al finalizar el contexto
Contenedor garantiza el mantenimiento del estado del bean dentro
del contexto
• Los ”clientes” donde se inyecta un bean CDI interact´uan siempre con el mismo objeto mientras el correspondiente contexto est´e activo
• Contenedor garantiza que desde el punto de vista de los clientes y dentro de un contexto dado existe una ´unica instancia de cada tipo de bean inyectado (CDI ofrece un especie singleton contextual)
Contexto de aplicaci´
on
@ApplicationScoped
Se prolonga durante la vida de la aplicaci´
on
Los beans CDI se crea en el momento en que arranca la aplicaci´
on y
se destruye al finalizar
Existe una ´
unica instancia de los beans compartida por todos los
”clientes”
Usado para funciones complementarias, cach´
es, etc
Puede presentar problemas de concurrencia
Contexto de sesi´
on
@SessionScoped
Se prolonga durante el conjunto de peticiones HTTP que se
corres-ponden con una sesi´
on de usuario
Vinculado al objeto
HttpSession
de la capa web
Los beans CDI se crean en su primer uso por parte del usuario
y se destruyen al finalizar la sesi´
on
(bien por una invocaci´on al m´etodoinvalidate() o por agotamiento de time-out de sesi´on)
Almacenan datos necesarios durante la sesi´
on de usuario
(credenciales de acceso, selecciones y preferencias, etc)Contexto de petici´
on
@RequestScoped
Vinculado a una petici´
on HTTP concreta
Vinculado al objeto
HttpServletRequest
de la capa web
Los beans CDI se crean al recibir la petici´
on y se destruyen con el
env´ıo de su respuesta
Mantienen datos que s´
olo son necesarios para la petici´
on actual
Es el m´
as utilizado
(la anotaci´on @Model combina las anotaciones@RequestScoped y @Named)
Contexto de conversaci´
on
@ConversationScoped
Contexto de duraci´
on variable, definida por la l´
ogica del bean
Todos los beans
@ConversationScoped
deben de inyectar un objeto
Conversation
a trav´
es del cu´
al se controla el contexto.
Existe desde que se invoca el m´
etodo
begin()
del objeto
Conversation
(normalmente en un m´etodo @PostContruct)hasta la
in-vocaci´
on del m´
etodo
end()
Utilizado para gestionar datos que se mantienen entre invocaciones
sucesivas del cliente, pero con un alcance menor que la sesi´
on, en el
caso de aplicaciones web
Contexto dependiente
@Dependent
Contexto por defecto
El bean CDI ”’hereda” el contexto en el cu´
al se encontraba el
”cliente” al que fue inyectado
(c) Ciclo de vida de beans en CDI
El contenedor CDI gestiona el ciclo de vida de los beans.
En la creaci´
on del bean, CDI se encarga (por este orden) de:
1. Crear el objeto invocando a su constructor vac´ıo o al etiquetado con @Inyect
2. Realizar la inyecci´on de las dependencias requeridas por las anotaciones
@Inyect del beanName
3. Invocar a los m´etodos anotados con @PostConstruct
En la destruci´
on del bean, CDI invoca a los m´
etodos anotados con
@PreDestroy
justo antes de eliminar el bean de la JVM.
Opcionalmente, CDI puede invocar a los interceptores de los m´
etodos
anotados con
@ArroundInvoke
o
@ArroundContruct
Interceptores
Los interceptores CDI ofrecen funcionalidades basadas en los principios
de la programaci´
on orienta a aspectos
(AOP: Aspect Oriented Programming)Suelen utilizarse para implementar funcionalidades que son comunes a varios componentes de la aplicaci´on (loging, transacciones, controles de seguridad, etc) Ofrecen un forma limita y muy espec´ıfica del patr´on Cadena de responsabilidad
1. Interceptores ”de clase”
En el propio bean se puede a˜nadir un interceptor propio marcando un m´etodo del bean con @ArroundInvoke o @ArroundsContruct
Ese m´etodo recibir´a un objeto InvocationContext con el cu´al acceder a infor-maci´on del m´etodo invocado
Mediante el m´etodo proceed() se indica que puede continuar su ejecuci´on public class ClienteService {
@Inject private EntityManager em; @Inject private Logger logger;
public void crearCliente (Cliente cliente) { em.persist(cliente);
} ...
@AroundInvoke private Object logMethod(InvocationContext ic) throws Exception { Logger.log("Entrando en clase "+ic.getTarget().toString()+
" con metodo "+ic.getMethod().getName()); try {
return ic.proceed(); } finally {
Logger.log("Saliendo de clase "+ic.getTarget().toString()+ " con metodo "+ic.getMethod().getName());
} } }
2. Interceptores generales
Lo m´as habitual es definir interceptores gen´ericos que podr´an emplearse en varios beans CDI
• marcando la clase que implementa los interceptores con@Interceptor
• definiendo una nueva anotaci´on (derivada de @InterceptorBinding) con la que vincular esa clase interceptora a los beans implicados
public class UsuarioService { private @Inject EntityManager em; @Transactional public almacenarUsuario(Usuario u) { em.persist(u); } } @Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.TYPE, ElementType.METHOD }) @InterceptorBinding
public @interface Transactional {}
@Interceptor @Transactional
public class TransactionalInterceptor { private @Inject EntityManager em; @AroundInvoke
public Object invoke(InvocationContext context) throws Exception{ EntityTransaction t =em.getTransaction(); try { if(!t.isActive()) { t.begin(); } return context.proceed(); } catch(Exception e) { t.rollback(); } finally {
if(t != null && t.isActive()) { t.commit();
} } } }
En ambos casos, para ser activados las clases que implementan los interceptores de-ber´an ser declaradas en el ficherobeans.xmldentro de etiquetas<interceptors>
(d) Decoradores y eventos
CDI incluye soporte a la implementaci´
on del
patr´
on Decorador
Decoradores similares en funcionamiento a los Interceptores (ampl´ıan las funciona-lidades de un objeto gestionado)
A diferencia de los Interceptores los Decoradores ”conocen” el inter-faz/comportamiento de la clase decorada
public interface TipoBasico { ... Metodos interfaz ... }
@Decorator
public class MiDecorador implements TipoBasico { @Inject @Delegate
private TipoBasico delegado; ... Metodos interfaz ... }
public class MiClase implements TipoBasico { ... Metodos interfaz ... } <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all"> <decorators>
CDI incluye soporte a la implementaci´
on del
patr´
on Observer
Permite vincular comportamiento a acciones/eventos que ocurran sobre los objetos gestionados
public class BookService { @Inject
private NumberGenerator numberGenerator; @Inject
-> private Event<Book> bookAddedEvent;
public Book createBook(String title, Float price, String description) { Book book = new Book(title, price, description);
book.setIsbn(numberGenerator.generateNumber()); -> bookAddedEvent.fire(book);
return book; }
}
public class InventoryService { @Inject
private Logger logger;
List<Book> inventory = new ArrayList<>(); -> public void addBook(@Observes Book book) {
logger.info("Adding book " + book.getTitle() + " to inventory"); inventory.add(book);
} }