El concepto de EJB Event pertenece a Java EE 6 . A partir de esta versión de la plataforma tenemos la posibilidad de generar eventos a nivel de EJBs. Esto es algo que en un principio parece extraño ya que estamos más acostumbrados a la gestión de eventos en el mundo de JavaScript y la web. ¿Para qué sirve la generación de eventos a nivel de EJBS?. Vamos a ver un ejemplo que nos ayude a entender la casuística. Supongamos que tenemos un Stateless Session Bean que se encarga de confirmar una compra VIP (ServicioCompra).
Estas compras VIP son muy importantes para nuestro negocio ya que identifican a nuestros mejores clientes. Por lo tanto cada vez que realizamos una compra VIP se realizan varias operaciones asociadas. En este caso se realiza un log especial, se envía un mensaje al comercial y envía al propio cliente un mensaje de bienvenido al servicio.
Vamos a ver el código Java utilizando 4 EJBS:
package com.arquitecturajava; import javax.ejb.Stateless; import javax.inject.Inject; @Stateless public class ServicioCompra { @Inject ServicioLog log; @Inject ServicioVip vip; @Inject ServicioAvisos avisos; public void confirmarCompra(Compra c) { System.out.println("compra guardada"); if (c.getImporte()>1000) { log.VIP(c); avisos.avisarComercial(); vip.mensajeVip(); } } }
package com.arquitecturajava; import javax.ejb.Stateless; @Stateless public class ServicioLog { public void VIP (Compra c) { System.out.println("COMPRA VIP"+ c.getImporte()); } }
package com.arquitecturajava; import javax.ejb.Stateless; @Stateless public class ServicioVip { public void mensajeVip() { System.out.println("bienvenido al servicio vip"); } }
package com.arquitecturajava; import javax.ejb.Stateless; @Stateless public class ServicioAvisos { public void avisarComercial() { System.out.println("compra importante avisa a un comercial"); } }
Todo funciona de una forma muy correcta y nuestro ServicioCompra invoca el resto de EJBS .Invocamos al EJB de ServicioCompras desde un Servlet.
Veamos su código:
package com.arquitecturajava; import java.io.IOException; import java.io.PrintWriter; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/miServlet") public class MiServlet extends HttpServlet { @Inject ServicioCompra sc; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); sc.confirmarCompra(new Compra("televisor", 1200)); pw.println("compra vip realizada"); } }
El resultado que nos saldrá en el navegador es:
La consola imprimirá los mensajes de ejecución de cada EJB.
¿Es mejorable el código que hemos construido? . El problema es que para ser un servicio tan importante de la aplicación y que puede variar mucho el EJB de Servicio compra tiene un acoplamiento muy fuerte y muy directo con los otros 3 servicios. En un futuro pueden ser más o incluso pueden variar los que ahora mismo funcionan. Esto hará que nuestro código sea muy frágil y de miedo modificar esta parte. ¿Cómo podemos enfocar de otra forma?
EJB Event , desacoplando servicios
Una buena solución es construir un EJB Event de tal forma que cuando la compra se realice y sobrepase los mil euros sea lanzado . Para luego poder utilizar servicios de EJB que escuchen este evento.
Vamos a verlo en código, el primer paso es generar el evento que contenga una compra:
package com.arquitecturajava; public class EventoCompraVip { private Compra compra; public Compra getCompra() { return compra; } public void setCompra(Compra compra) { this.compra = compra; } public EventoCompraVip(Compra compra) { super(); this.compra = compra; } }
El siguiente paso es lanzarlo desde un EJB :
package com.arquitecturajava; import javax.enterprise.event.Event; import javax.inject.Inject; public class ServicioCompra { @Inject Event<EventoCompraVip> misEventos; public void confirmarCompra(Compra c) { System.out.println("compra guardada"); if (c.getImporte()>1000) { misEventos.fire(new EventoCompraVip(c)); } } }
Por último nos queda diseñar uno o mas listener que se encarguen de gestionar el evento:
package com.arquitecturajava.listener; import javax.ejb.Stateless; import javax.enterprise.event.Observes; import javax.inject.Inject; import com.arquitecturajava.EventoCompraVip; import com.arquitecturajava.ServicioAvisos; import com.arquitecturajava.ServicioLog; @Stateless public class ServicioAvisosListener { @Inject ServicioAvisos servicio; public void escuchaCompra(@Observes EventoCompraVip evento) { servicio.avisarComercial(); } }
package com.arquitecturajava.listener; import javax.ejb.Stateless; import javax.enterprise.event.Observes; import javax.inject.Inject; import com.arquitecturajava.EventoCompraVip; import com.arquitecturajava.ServicioLog; @Stateless public class ServicioListenerLog { @Inject ServicioLog servicio; public void escuchaCompra(@Observes EventoCompraVip evento) { System.out.println("COMPRA VIP"+ evento.getCompra().getImporte()); } }
El resultado cuando ejecutemos el servlet , mostrará la ejecución de los listeners de ese EJB Event, hemos desacoplados los EJB:
El uso de los EJB Event es muy práctico cuando queremos desacoplar elementos y añadir flexibilidad:
Otros artículos relacionados:
Hola Cecilio,
Te felicito por el articulo esta fenomenal, pero quisiera me orientaras en un tema al respecto es sobre un proceso de envio de notificaciones por email ¿Cual cres que sea mejor solución el uso de EJB events o el uso de JMS (Queue) ?
saludos.
Si la petición es sincrona EJB event si es asíncrona jms 🙂
Muchas gracias.. Buen aporte.
de nada 🙂
Gracias!!
de nada 🙂
Hola Cecilio, muy buen articulo.
Existe alguna limitacion en el uso de EJB events? A parte de los ejemplos dados, cuales son los usos más frecuentes de este tipo de soluciones?
Muchas Gracias.
En principio no existe limitación son parte del standard , sirven para abordar situaciones en las que quizás jms es demasiado y ayudan a desacoplar el código. Pero permiten muchas opciones como aquí se puede ver.
Muy buen articulo, muchas gracias
gracias 🙂
Buenas Cecilio, magnifica explicación muchas gracias. ¿Se podria decir que es un implementacion del patron observador?
si claramente 🙂