DevLife

Java Message Service (JMS)

¿Qué es JMS?

JMS es un servicio de mensajería en Java. Es una API en Java que permite a una aplicación enviar mensajes con otras aplicaciones.

Conceptualmente pensemos en JPA, en donde ésta es una API estándar e Hibernate es la implementación, esto es similar a JMS, donde ésta es una API estándar que requiere una implementación subyacente a ser proporcionada.

JMS es altamente escalable y permite evitar el acoplamiento entre aplicaciones usando mensajería asíncrona.

Algunas implementaciones JMS:

  • Amazon SQS
  • Apache ActiveMQ
  • JBoss Messaging
  • RabbitMQ
  • Entre muchas otras.

¿Por qué utilizar JMS?

Si bien es cierto que esta mensajería se podría hacer vía REST, JMS proporciona algunas ventajas al ser un servicio específico de mensajería.

Algunas ventajas son:

  • Es asíncrono.
  • Tiene una mejor performance que utilizar protocolo HTTP.
  • Hay flexibilidad en la entrega de mensajes.
  • Es muy confiable, posee una gran robustez cuando hablamos de seguridad.

Tipos de Mensajería

Hay algunos tipos de mensajería que debemos revisar:

Mensajería Point
  • El mensaje es encolado y entregado a un consumidor.
  • Se puede tener múltiples consumidores, pero el mensaje debe ser entregado sólo una vez.
  • Los consumidores se conectan a una cola.
MENSAJERÍA Publish / Subscribe
  • El mensaje es entregado a uno o más suscriptores.
  • Los suscriptores se suscribirán a un tópico, y luego recibirán una copia de todos los mensajes enviados a dicho tópico.

Términos Clave

  • JMS Provider: Es la implementación JMS utilizada.
  • JMS Client:Es la aplicación que envía o recibe mensajes desde un JMS provider.
  • JMS Producer or Publisher: Es el JMS Client que envía mensajes.
  • JMS Consumer / Subscriber: Es el JMS client que recibe mensajes.
  • JMS Message: Es la entidad de la data enviada.
  • JMS Queue: Es la cola de los mensajes point to point. Algunas veces es FIFO.
  • JMS Topic: Similar a una cola, pero para publicar y suscribir.

Mensaje JMS

Un mensaje JMS, contiene tres partes:

  • Header: Contiene metadata del mensaje.
    • JMSCorrelationID (Para tracear un mensaje entre múltiples consumidores).
    • JMSExpires: Se puede setear que un mensaje será borrado después de algún tiempo.
    • JMSMessageId: Seteado por el JMS Provider.
    • JMSPriority: Prioridad del mensaje.
    • JMSTimestamp: Fecha en que se envía el mensaje.
    • JMSType: Tipo de mensaje
    • JMSReplyTo: Queue o tópico donde el sender está esperando respuestas,
    • Otras más…
  • Properties: Las propiedades vienen en tres secciones:
    • Application: De la aplicación Java que envía el mensaje.
    • Provider: Usada por el proveedor JMS y la implementación específica.
    • Standar Properties: Definido por la API JMS.
  • Payload: El mensaje.

Hay muchos campos de Application Properties, Standar Properties y Headers que puede tener un mensaje JMS. Acá solo se revisaron algunos.

Tipos de Mensaje JMS

  • Message: Sólo un mensaje, sin payload. Usado para notificar sobre eventos.
  • BytesMessage: El Payload es un array de bytes.
  • TextMessage: El message está almacenado como un string como un json o xml.
  • StreamMessage: Una secuencia de primitivos Java.
  • MapMessage: El mensaje es nombre en pares de valores.
  • ObjectMessage: El mensaje es un objeto java serializado.

Hoy en día los payloads más populares son los JMS TextMessages, ya que están desacoplados de Java, y un JSON puede ser consumido por cualquier otra tecnología.

Manos a la obra

Ya sabiendo un poco más sobre JMS, veamos qué tal se ve en código.

Vamos a partir creando un nuevo proyecto Spring a partir de un Spring Initializr:

Creación de proyecto Spring
Creación de Proyecto Spring – 2
Creación de Proyecto Spring – Dependencias

Hasta aquí lo único nuevo que tiene es que estamos seleccionando una librería de Spring para que utilicemos ActiveMQ.

Con esto ya estamos listos con nuestro entorno de trabajo:

Proyecto Inicial.

Para nuestro proyecto, querremos levantar un servidor embebido sobre el cual probar las características de JMS, para ello debemos agregar unas nuevas dependencias en nuestro pom:

        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-jms-server</artifactId>
        </dependency>

Listo!!!

Lo primero que haremos es crearnos un POJO para nuestro mensaje JMS:

Sólo creamos un POJO simple, dentro de un nuevo package model con dos campos. A todo esto, con lombok, le generamos los getters y setters, el patrón builder y los constructores con y sin argumentos. Este POJO no sólo enviará mensajes, sino que los recibirá, por lo cual, también implementamos un Serializable.

Haremos una configuración básica para levantar nuestro servidor MQ Server. Para esto, lo haremos dentro del método main y hacemos las configuraciones básicas:

Todo esto sale directamente desde la documentación de ActiveMQ sobre cómo levantar un servidor embebido. Lo que hicimos fue configurar un pequeño y básico servidor ActiveMQServer.

Ojo que esto es sólo para fines educativos, generalmente se tendrá un servidor MQ externo, fuera de Spring Boot y sólo buscamos poder enviar un mensaje JMS y recibir uno.

Task Configuration

Ahora que nuestro servidor de pruebas está levantado, configuraremos un ejecutor de tareas para Spring, y lo que lograremos será que estaremos mandando un mensaje periódicamente.

Creamos una nueva clase de configuración con las anotaciones @EnableScheduling y @EnableAsync estas anotaciones configurarán Spring para hacer tareas desde un task pool. La anotación @Configuration, le está diciendo a Spring que tome esta clase de configuración, y escanee los métodos anotados como @Bean.

Así tendremos nuestro Bean Task Executor inyectado al Spring Context, y así Spring utilizará esto para ejecutar tareas por nosotros de forma periódica.

Message Converter Configuration

Crearemos ahora una nueva clase llamada JmsConfig. Acá declararemos un Bean llamado messageConverter en el Spring Context. Y esto será un mapper de Jackson a mensaje, específicamente para trabajar con la librería Jackson JSON.

Lo que hará Spring con esto, es que cuando enviemos un mensaje a JMS, Spring lo convertirá a un mensaje de texto de JMS, y el payload tomará ese objeto Java y lo convertirá a JSON plano.

Eso es lo que esta configuración está haciendo, habilita nuestra instancia Spring para que realice esta conversión, y lo mismo cuando llega un mensaje JMS de tipo texto, lo convierta de vuelta a un objeto Java.

Enviar mensajes JMS

Lo primero, es tener seteado un nombre para nuestra cola, esto puede hacerse en la misma clase de configuración de JMS:

Ahora crearemos una clase encargada de enviar los mensajes:

¿Qué está pasando aquí?

Hemos marcado la clase como un @Component Spring, e inyectado un JmsTemplate (que está configurado para hablar con nuestra instancia ActiveMQ). También, tenemos un método llamado SendMessage, que está configurado para ejecutarse cada 2 segundos.

Dentro de este método estamos creando un nuevo elemento de nuestro POJO HelloWorldMessage, y construyéndolo con nuestro Builder de Lombok.

Finalmente, le estamos diciendo a JmsTemplate, que haga la conversión (que hicimos anteriormente en el Message Converter. Y diciéndole que convierte este archivo a tipo Text y lo envíe a la cola que hemos definido.

Si ejecutamos nuestra app, podemos ver en la consola algo como esto:

¡¡¡¡Está funcionando!!!!

Recibir JMS Messages

Ya vimos como enviar mensajes, y lo que nos gustaría ahora es, poder capturarlos. Lo que debemos hacer es configurar un Message Listener, y esto es muy simple dentro de Spring.

Veamos qué hicimos aquí. Primero, creamos una nueva clase y la marcamos como @Component, luego creamos un método listen y lo anotamos como @JmsListener y como parámetro le dimos el nombre de nuestra cola, a la que se conectará.

En la declaración del método vemos que recibiremos un HelloWorldMessage, los headers del mensaje. La anotación @Payload le indica a Spring que puede deserializar el objeto, así como la anotación @Headers le indica que puede extraer los headers del mensaje.

Finalmente, sólo estamos llamando al POJO e imprimiéndolo, si ejecutamos la aplicación ahora nos dará en la consola que se envió el mensaje e instantáneamente, lo recibirá:

Finalmente el objeto Message que no explicamos es sólo el objeto JMS como tal. Si ejecutamos un debug e inspeccionamos los elementos podemos ver lo siguiente:

Conclusiones

Ya hemos visto lo que puede hacer JMS por nosotros. Esto es muy interesante, y sólo dimos un vistazo a todo el potencial que tiene. Próximamente, haré la parte dos de este documento, con ejemplos más complejos, levantando un ActiveMQ en Docker y conectándolo con Spring y veremos comunicación entre micro servicios y más.

Repositorio Github

Finalmente, les dejo el repo de github donde está el ejemplo funcional:

https://github.com/gonzaloan/jmsdemo.git

Categories: DevLife, Java, Spring

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s