![CDATA[
La integración de Spring con RabbitMQ permite enviar y recibir mensajes de forma desacoplada. En esta guía crearemos dos proyectos Maven independientes, uno para el productor y otro para el consumidor, utilizando la biblioteca spring-rabbit y configuración XML.
Dependencias comunes
Ambos proyectos necesitan las mismas dependencias en el archivo pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.7.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
Archivo de propiedades
Ambos módulos comparten un fichero conexion.properties con los datos del bróker:
rabbitmq.host=192.168.50.20
rabbitmq.port=5672
rabbitmq.username=invitado
rabbitmq.password=invitado
rabbitmq.virtual-host=/demo
Configuración del productor
En el proyecto productor se define el contexto spring-productor-rabbit.xml con las colas e intercambiadores necesarios:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<context:property-placeholder location="classpath:conexion.properties"/>
<rabbit:connection-factory id="fabricaConexion"
host="${rabbitmq.host}" port="${rabbitmq.port}"
username="${rabbitmq.username}" password="${rabbitmq.password}"
virtual-host="${rabbitmq.virtual-host}"/>
<rabbit:admin connection-factory="fabricaConexion"/>
<!-- Cola simple (default exchange) -->
<rabbit:queue id="colaSimple" name="colaSimple" auto-declare="true"/>
<!-- Fanout: colas e intercambiador -->
<rabbit:queue id="colaNoticias1" name="cola.noticias1" auto-declare="true"/>
<rabbit:queue id="colaNoticias2" name="cola.noticias2" auto-declare="true"/>
<rabbit:fanout-exchange id="fanoutNoticias" name="fanout.noticias" auto-declare="true">
<rabbit:bindings>
<rabbit:binding queue="cola.noticias1"/>
<rabbit:binding queue="cola.noticias2"/>
</rabbit:bindings>
</rabbit:fanout-exchange>
<!-- Topic: colas e intercambiador con patrones -->
<rabbit:queue id="colaInfoSistema" name="cola.info.sistema" auto-declare="true"/>
<rabbit:queue id="colaTodoSistema" name="cola.todo.sistema" auto-declare="true"/>
<rabbit:queue id="colaTodoSistema2" name="cola.todo.sistema2" auto-declare="true"/>
<rabbit:topic-exchange id="topicSistema" name="topic.sistema" auto-declare="true">
<rabbit:bindings>
<rabbit:binding pattern="sistema.*" queue="cola.info.sistema"/>
<rabbit:binding pattern="sistema.#" queue="cola.todo.sistema"/>
<rabbit:binding pattern="sistema.#" queue="cola.todo.sistema2"/>
</rabbit:bindings>
</rabbit:topic-exchange>
<rabbit:template id="plantillaRabbit" connection-factory="fabricaConexion"/>
</beans>
Prueba del productor
La clase de test envía mensajes a las distintas colas e intercambiadores:
package com.ejemplo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-productor-rabbit.xml")
public class ProductorPrueba {
@Autowired
private RabbitTemplate plantillaRabbit;
@Test
public void enviarAColaSimple() {
plantillaRabbit.convertAndSend("colaSimple", "Mensaje simple");
}
@Test
public void enviarFanout() {
plantillaRabbit.convertAndSend("fanout.noticias", "", "Noticia urgente");
}
@Test
public void enviarTopic() {
plantillaRabbit.convertAndSend("topic.sistema", "sistema.alerta", "Alerta del sistema");
}
}
Configuración del consuimdor
El proyecto consumidor declara los listeners y los asocia con las colas en spring-consumidor-rabbit.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<context:property-placeholder location="classpath:conexion.properties"/>
<rabbit:connection-factory id="fabricaConexion"
host="${rabbitmq.host}" port="${rabbitmq.port}"
username="${rabbitmq.username}" password="${rabbitmq.password}"
virtual-host="${rabbitmq.virtual-host}"/>
<bean id="oyenteSimple" class="com.ejemplo.rabbit.listeners.OyenteSimple"/>
<bean id="oyenteNoticias1" class="com.ejemplo.rabbit.listeners.OyenteNoticias1"/>
<bean id="oyenteNoticias2" class="com.ejemplo.rabbit.listeners.OyenteNoticias2"/>
<bean id="oyenteInfoSistema" class="com.ejemplo.rabbit.listeners.OyenteInfoSistema"/>
<bean id="oyenteTodoSistema" class="com.ejemplo.rabbit.listeners.OyenteTodoSistema"/>
<bean id="oyenteTodoSistema2" class="com.ejemplo.rabbit.listeners.OyenteTodoSistema2"/>
<rabbit:listener-container connection-factory="fabricaConexion" auto-declare="true">
<rabbit:listener ref="oyenteSimple" queue-names="colaSimple"/>
<rabbit:listener ref="oyenteNoticias1" queue-names="cola.noticias1"/>
<rabbit:listener ref="oyenteNoticias2" queue-names="cola.noticias2"/>
<rabbit:listener ref="oyenteInfoSistema" queue-names="cola.info.sistema"/>
<rabbit:listener ref="oyenteTodoSistema" queue-names="cola.todo.sistema"/>
<rabbit:listener ref="oyenteTodoSistema2" queue-names="cola.todo.sistema2"/>
</rabbit:listener-container>
</beans>
Implementación de los listeners
Cada oyente procesa el mansaje recibido. Ejemplo de OyenteSimple:
package com.ejemplo.rabbit.listeners;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
public class OyenteSimple implements MessageListener {
@Override
public void onMessage(Message message) {
System.out.println("OyenteSimple: " + new String(message.getBody()));
}
}
Los demás oyentes siguen la misma estructura, mostrando un mensaje identificador en la consola.
Arranque del consumidor
El consumidor permanece a la escucha mediante un bucle infinito en la prueba:
package com.ejemplo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-consumidor-rabbit.xml")
public class ConsumidorPrueba {
@Test
public void mantenerEscucha() {
while (true) {
// el listener-container gestiona la recepción en segundo plano
}
}
}
Al ejecutar este test y luego lanzar los métodos del productor, los mansajes aparecerán en la consola del consumidor.
]]>