En esta entrada vamos a ver como configurar (de forma rápida), como configurar colas con Spring y un gestor de colas, como es el caso de Apache ActiveMQ, para enviar y recibir mensajes. Para ello, podéis descargar:
-
La versión 5.7.0 de ActiveMQ
-
Tomcat 7
Os creáis un proyecto
Maven con la siguiente configuración:
En el pom.xml, la dependencia a
Spring y al core de
ActiveMQ:
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<artifactId>spring-activemq-sample</artifactId>
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<groupId>papidal</groupId>
<version>1.0</version>
<properties>
<releaseCandidate>1</releaseCandidate>
<spring.version>3.1.1.RELEASE</spring.version>
<java.version>1.5</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.javadoc.reporting.version>2.7</maven.javadoc.reporting.version>
<commons.logging.version>1.1.1</commons.logging.version>
<log4j.version>1.2.16</log4j.version>
<context.path>spring-activemq-sample</context.path>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>${context.path}</warName>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>3.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-asm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
Un contexto, context.xml, en el que estarán vuestras colas de entrada y salida, así como la conexión al gestor de colas:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!--
Conexión ActiveMQ
-->
<Resource name="jms/mqConnectionFactory"
auth="Container"
type="org.apache.activemq.ActiveMQConnectionFactory"
description="JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="tcp://localhost:61616" />
<!-- Cola 1 -->
<Resource name="jms/testQueueOne"
auth="Container"
type="org.apache.activemq.command.ActiveMQQueue"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
physicalName="TestQueueOne"/>
<!-- Cola 2 -->
<Resource name="jms/testQueueTwo"
auth="Container"
type="org.apache.activemq.command.ActiveMQQueue"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
physicalName="TestQueueTwo"/>
</Context>
El resto de configuración, en spring-config.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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<!-- Recursos jndi -->
<jee:jndi-lookup id="mqConnectionFactory" jndi-name="java:comp/env/jms/mqConnectionFactory" />
<jee:jndi-lookup id="testQueueOne" jndi-name="java:comp/env/jms/testQueueOne" />
<jee:jndi-lookup id="testQueueTwo" jndi-name="java:comp/env/jms/testQueueTwo" />
<!-- Clase que recibe los mensajes -->
<bean id="testMessageListener" class="papidal.TestMessageListener">
<property name="testMessageSender" ref ="testMessageSender" />
</bean>
<bean id="poiMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref ="mqConnectionFactory" />
<property name="destination" ref ="testQueueOne"/>
<property name="messageListener" ref ="testMessageListener"/>
<property name="concurrentConsumers" value="2" />
</bean>
<!-- Clase que envía los mensajes -->
<bean id="testMessageSender" class="papidal.TestMessageSender">
<property name="jmsTemplate" ref="jmsTemplate"/>
<property name="testQueue" ref="testQueueTwo"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="mqConnectionFactory" />
</bean>
</beans>
En el web.xml, indicáis dónde tenemos la configuración de spring:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID"
version="2.5">
<!--
Fichero de configuración de spring
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/spring-config.xml
</param-value>
</context-param>
<!--
Cargamos el contexto de Spring
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
La clase que escucha en la cola 1, los mensaje que llegan:
package papidal;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.apache.log4j.Logger;
public class TestMessageListener implements MessageListener
{
private TestMessageSender messageSender_i;
private static final Logger logger_c = Logger.getLogger(TestMessageListener.class);
//Escucha los mensajes
public void onMessage(Message message)
{
logger_c.info("Recibo mensaje de la cola [" + message +"]");
if (message instanceof TextMessage)
{
try
{
String msgText = ((TextMessage) message).getText();
logger_c.debug("Mensaje recibido: " + msgText);
messageSender_i.sendMessage(msgText);
}
catch (JMSException jmsEx_p)
{
String errMsg = "Error obteniendo el mensaje";
logger_c.error(errMsg, jmsEx_p);
}
}
else
{
String errMsg = "El mensaje no es del tipo TextMessage";
logger_c.error(errMsg);
throw new RuntimeException(errMsg);
}
}
public void setTestMessageSender(TestMessageSender messageSender_p)
{
this.messageSender_i = messageSender_p;
}
}
La clase que usamos para enviar los mensajes recibidos hacia la cola 2:
package papidal;
import javax.jms.JMSException;
import javax.jms.Queue;
import org.apache.log4j.Logger;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
// Enviamos mensajes a una cola
@Service
public class TestMessageSender
{
private JmsTemplate jmsTemplate_i;
private Queue testQueue_i;
private static final Logger logger_c = Logger .getLogger(TestMessageSender.class);
// Envio del mensaje
public void sendMessage(String message_p) throws JMSException
{
logger_c.debug("Ponemos el mensaje en la cola[" + testQueue_i.toString() + "] Mensaje[" + message_p + "]");
jmsTemplate_i.convertAndSend(testQueue_i, message_p);
}
public void setJmsTemplate(JmsTemplate tmpl)
{
this.jmsTemplate_i = tmpl;
}
public void setTestQueue(Queue queue)
{
this.testQueue_i = queue;
}
}
Levantáis el gestor de colas:
"D:\apache-activemq-5.7.0\bin\activemq.bat"
Para administrar:
Simplemente con levantar el servidor ya veremos la cola 1 (en mi caso, un Tomcat 7) con 2 consumidores.
Le damos a "send To", metemos cualquier cosa (típicamente un xml) y vemos que por la
consola de Tomcat hemos recibido el mensaje correctamente, que hemos enviado
por la cola 1 y que lo hemos a su vez enviado a la cola 2.
En el ActiveMQ podemos
verlo también (fijaros en la columna de encolados y desencolados. Como la cola
para enviar mensajes es la dos, y nosotros escuchamos sólo la 1, la cola 2 no
tiene consumidores activos ya que sólo la usamos para enviar mensajes. Si algún
modulo quiere escucharla, no hay problema).
Acordaros de darle a F5 para
refrescar la pantalla ;)
A partir de aquí, se pueden definir canales, jugar con el xpath para aceptar o descartar mensajes en función del identificador del envoltorio, usar jaxb para hacer marshall/unmarshall, definir el encoding del parseo de xml a clases Java y viceversa, ...