En este tutorial se explica cómo integrar RabbitMQ con Spring.
Índice de contenidos
- 1. Introducción
- 2. Entorno
- 3. Servidor de RabbitMQ
- 4. Creación del proyecto en IntelliJ IDEA
- 5. Implementación
- 6. Ejecución
- 7. Conclusiones
- 8. Referencias
1. Introducción
En su tutorial Implementación de Emisor y Receptor básicos con RabbitMQ, José Luis explicó los conceptos básicos de RabbitMQ. En este tutorial, lo que vamos a hacer es mostrar cómo se integra RabbitMQ en un proyecto Spring con Spring Boot.
2. Entorno
Este tutorial se ha desarrollado en el siguiente entorno:
- Hardware: portátil MacBook Pro (15′, mediados 2010).
- Sistema operativo: Mac OS X Yosemite 10.10.5.
- IDE: IntelliJ IDEA 14 Ultimate.
- Versión de Java: 1.8.0_60
3. Servidor de RabbitMQ
Empezamos instalando el servidor de RabbitMQ. Lo descargamos de aquí o, si utilizamos Mac, de aquí o a través de Homebrew:
$ brew install rabbitmq
Ahora queremos ejecutar el script rabbitmq-server. Si has descargado RabbitMQ manualmente, se encontrará en «rabbitmq_server-x.y.z/sbin/». Si lo has instalado con Homebrew en Mac, la ruta será «/usr/local/Cellar/rabbitmq/x.y.z/sbin/». En todo caso, podemos añadir al path la ruta de esta carpeta para poder ejecutar rabbitmq-server desde cualquier directorio en la terminal, en lugar de tener que ir hasta «sbin/».
Arrancamos el servidor de RabbitMQ:
$ rabbitmq-server
y nos saldrá:
RabbitMQ x.y.z. Copyright (C) 2007-2015 Pivotal Software, Inc. ## ## Licensed under the MPL. See http://www.rabbitmq.com/ ## ## ########## Logs: /usr/local/var/log/rabbitmq/rabbit@localhost.log ###### ## /usr/local/var/log/rabbitmq/rabbit@localhost-sasl.log ########## Starting broker... completed with 10 plugins.
4. Creación del proyecto en IntelliJ IDEA
Lo primero que vamos a hacer es crear un proyecto Spring Boot. Spring Boot nos sirve para crear y ejecutar aplicaciones Spring de una manera más sencilla.
En nuestro caso, empleamos IntelliJ IDEA como IDE. Seguimos los pasos mostrados en las capturas de pantalla:
Tras crear el proyecto nos saldrá un mensaje pidiendo que añadamos el pom.xml como proyecto Maven.
Este mensaje también lo podemos ver si hacemos clic en la parte inferior izquierda del IDE.
Lo añadimos y esperamos a que IntelliJ sincronice automáticamente las dependencias.
En este momento ya tenemos una aplicación que se puede ejecutar (el método main usa SpringApplication.run para ejecutarla). Lo comprobamos haciendo clic derecho en el archivo TutorialRabbitmqSpringApplication.java y dándole a «Run / TutorialRabbitmqSpringApplication».
El archivo pom.xml lo modificamos para dejarlo de la siguiente manera:
4.0.0 tutoriales.rabbitmq.spring tutorial-rabbitmq-spring 0.0.1-SNAPSHOT jar tutorial-rabbitmq-spring RabbitMQ con Spring org.springframework.boot spring-boot-starter-parent 1.2.6.RELEASE UTF-8 1.8 org.springframework.boot spring-boot-starter-amqp 1.2.6.RELEASE org.springframework.boot spring-boot-maven-plugin
5. Implementación
El proyecto va a constar de tres clases: TutorialRabbitmqSpringApplication, Receiver y RabbitMqConfig. El código de ejemplo está en este repositorio de GitHub.
Receiver.java
package tutoriales.rabbitmq.spring; public class Receiver { public static final String RECEIVE_METHOD_NAME = "receiveMessage"; public void receiveMessage(String message) { System.out.println("[Receiver] ha recibido el mensaje \"" + message + '"'); } }
Receiver simplemente se encarga de imprimir el mensaje recibido.
RabbitMqConfig.java
package tutoriales.rabbitmq.spring; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.Queue; import org.springframework.amqp.core.TopicExchange; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMqConfig { public static final String EXCHANGE_NAME = "exchange_name"; public static final String ROUTING_KEY = "routing_key"; private static final String QUEUE_NAME = "queue_name"; private static final boolean IS_DURABLE_QUEUE = false; @Bean Queue queue() { return new Queue(QUEUE_NAME, IS_DURABLE_QUEUE); } @Bean TopicExchange exchange() { return new TopicExchange(EXCHANGE_NAME); } @Bean Binding binding(Queue queue, TopicExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY); } @Bean SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames(QUEUE_NAME); container.setMessageListener(listenerAdapter); return container; } @Bean Receiver receiver() { return new Receiver(); } @Bean MessageListenerAdapter listenerAdapter(Receiver receiver) { return new MessageListenerAdapter(receiver, Receiver.RECEIVE_METHOD_NAME); } }
La clase RabbitMqConfig viene anotada con @Configuration para indicar a Spring que contendrá definiciones de beans, los cuales son aquellos métodos que están anotados con @Bean. Vamos a ver para qué sirve cada uno:
@Bean Queue queue() { return new Queue(QUEUE_NAME, IS_DURABLE_QUEUE); }
Crea una cola a la que le otorga un nombre y le define su durabilidad.
@Bean TopicExchange exchange() { return new TopicExchange(EXCHANGE_NAME); }
Crea un exchange de tipo topic y le asigna un nombre.
@Bean Binding binding(Queue queue, TopicExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY); }
Enlaza una cola con un exchange de tipo topic. Con with se define la clave del enlace.
@Bean SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames(QUEUE_NAME); container.setMessageListener(listenerAdapter); return container; }
Contenedor en el que se indican quiénes son los consumidores de las colas.
@Bean Receiver receiver() { return new Receiver(); }
Receptor del mensaje.
@Bean MessageListenerAdapter listenerAdapter(Receiver receiver) { return new MessageListenerAdapter(receiver, Receiver.RECEIVE_METHOD_NAME); }
Adaptador para indicar quién recibe el mensaje y qué método lo procesa.
Nota: si te aparece el aviso de que el contexto de la aplicación no está configurado para RabbitMqConfig, como se ve en la siguiente imagen:
entonces deberás ir a «File / Project Structure… / Project Settings / Modules»:
hacer clic derecho en «tutorial-rabbitmq-spring», «Add / Spring»:
y seguir estos pasos:
TutorialRabbitmqSpringApplication.java
package tutoriales.rabbitmq.spring; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class TutorialRabbitmqSpringApplication implements CommandLineRunner { private static final String MESSAGE = "Hello world!"; @Autowired RabbitTemplate rabbitTemplate; public static void main(String[] args) { SpringApplication.run(TutorialRabbitmqSpringApplication.class, args); } @Override public void run(String... args) throws InterruptedException { System.out.println("[Application] Enviando el mensaje \"" + MESSAGE + "\"..."); rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_NAME, RabbitMqConfig.ROUTING_KEY, MESSAGE); } }
La clase TutorialRabbitmqSpringApplication está anotada con @SpringBootApplication. Esta anotación, propia de Spring Boot, equivale a añadir las siguientes:
- @Configuration. Indica que contiene beans.
- @EnableAutoConfiguration. Activa la autoconfiguración del contexto de aplicación de Spring para que busque los beans que se van a necesitar.
- @ComponentScan. Dice a Spring que busque componentes, configuraciones y servicios en el paquete de la clase.
Con la anotación @Autowired, incluimos el bean RabbitTemplate que nos proporciona Spring. En concreto, este template nos ayuda a enviar y recibir mensajes de una manera realmente sencilla: a través del método convertAndSend indicamos que queremos enviar el mensaje MESSAGE a las colas que tengan un enlace al exchange EXCHANGE_NAME con clave ROUTING_KEY.
5.1. Configuración de RabbitMQ
La conexión con el servidor de RabbitMQ se puede configurar a través del archivo application.properties, que admite las siguientes propiedades:
application.properties
# RabbitMQ properties spring.rabbitmq.host= spring.rabbitmq.port= spring.rabbitmq.addresses= spring.rabbitmq.username= spring.rabbitmq.password= spring.rabbitmq.virtual-host= spring.rabbitmq.dynamic=
Si se omiten, por defecto tomará: localhost, el puerto 5672, el usuario guest, la contraseña guest y el host virtual /.
6. Ejecución
Lo primero es ejecutar el servidor de RabbitMQ con rabbitmq-server si no lo hemos hecho antes. Entonces ya podremos iniciar la aplicación.
Por consola, además de la salida propia de Spring Boot, deberá aparecer:
[Application] Enviando el mensaje "Hello world!"... [Receiver] ha recibido el mensaje "Hello world!"
7. Conclusiones
La integración de RabbitMQ con Spring no tiene ninguna dificultad, pues en un rato hemos sido capaces de crear desde cero un proyecto que se sirve del framework Spring para enviar mensajes a través de RabbitMQ.
Hola el ejemplo mostrado está interesante pero veo que envía como el que recibe el mensaje son parte de la misma solución.
Si yo quisiera hacer que el mensaje sea enviado por ejemplo desde un servicio y en ese momento haga PUT del mensaje en el RabbitServer, y dicho mensaje sea obtenido desde otro servicio, como podría adaptar esta solución.