前一篇中我们介绍了使用RabbitMQ Java Client访问RabbitMQ的方法。但是使用这种方式访问RabbitMQ,开发者在程序中需要自己管理Connection,Channel对象,Consumer对象的创建,销毁,这样会非常不方便。我们下面介绍使用Spring AMQP连接RabbitMQ,进行消息的接收和发送。
Spring AMQP是一个Spring子项目,它提供了访问基于AMQP协议的消息服务器的解决方案。它包含两部分,spring-ampq是基于AMQP协议的消息发送和接收的高层实现,spring-rabbit是基于RabbitMQ的具体实现。这两部分我们下面都会使用到。
Spring-AMQP中的基础类/接口
spring-amqp中定义了几个基础类/接口,Message,Exchange,Queue,Binding
Message
public class Message implements Serializable
{
private final MessageProperties messageProperties;
private final byte[] body;
spring-amqp中的Message类类似于javax的Message类,封装了消息的Properties和消息体。
Exchange
spring-amqp定义了Exchange接口
这个接口和RabbitMQ Client中的Exchange类相似。 spring-amqp中的Exchange继承关系如下图所示public interface Exchange extends Declarable { //Exchange名称 String getName(); //Exchange的类型 String getType(); //Exchange是否持久化 boolean isDurable(); //Exchange不再被使用时(没有任何绑定的情况下),是否由RabbitMQ自动删除 boolean isAutoDelete(); //Exchange相关的参数 Map<String, Object> getArguments();
Queue
spring-amqp定义了Queue类,和RabbitMQ Client中的Queue相似,对应RabbitMQ中的消息队列。
public class Queue extends AbstractDeclarable {
private final String name;
private final boolean durable;
private final boolean exclusive;
private final boolean autoDelete;
private final java.util.Map<java.lang.String, java.lang.Object> arguments;
public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete) {
this(name, durable, exclusive, autoDelete, null);
}
Binding
Binding类是对RabbitMQ中Exchange-Exchange以及Exchange-Queue绑定关系的抽象。
public class Binding extends AbstractDeclarable
{
public enum DestinationType {
QUEUE, EXCHANGE;
}
private final String destination;
private final String exchange;
private final String routingKey;
private final Map<String, Object> arguments;
private final DestinationType destinationType;
public Binding(String destination, DestinationType destinationType, String exchange, String routingKey,
Map<String, Object> arguments) {
this.destination = destination;
this.destinationType = destinationType;
this.exchange = exchange;
this.routingKey = routingKey;
this.arguments = arguments;
}
对照RabbitMQ Java Client中Channel接口的queueBind和ExchangeBind方法
Exchange.BindOk exchangeBind(String destination, String source, String routingKey, Map<String, Object> arguments)
Queue.BindOk queueBind(String queue, String exchange, String routingKey, Map<String, Object> arguments)
我们可以看出Binding类实际是对底层建立的Exchange-Queue和Exchange-Exchange绑定关系的高层抽象记录类,它使用枚举类型DestinationType区分Exchange-Queue和Exchange-Exchange两种绑定。
Spring AMQP搭建消费者应用
消费者应用程序框架搭建
我们接下来使用spring-amqp搭建一个RabbitMQ的消费者Web应用,我们先创建一个maven webapp应用程序,再添加一个dependency。
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.6.5.RELEASE</version>
</dependency>
spring-rabbit库的引入是为了使用它里面的RabbitAdmin类,创建Exchange,Queue和Binding对象,在导入这个库的时候同时引入了 spring-ampq和rabbitmq-client的库,不需要另行导入。
在src/main/resources目录下创建application.properties文件,用于记录RabbitMQ的配置信息。
mq.ip=localhost
mq.port=5672
mq.userName=rabbitmq_consumer
mq.password=123456
mq.virutalHost=test_vhosts
在src/main/resource目录下创建applicationContext.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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd" >
<context:annotation-config/>
<context:property-placeholder
ignore-unresolvable="true" location="classpath*:/application.properties" />
<!--从RabbitMQ Java Client创建RabbitMQ连接工厂对象-->
<bean id="rabbitMQConnectionFactory" class="com.rabbitmq.client.ConnectionFactory">
<property name="username" value="${mq.userName}" />
<property name="password" value="${mq.password}" />
<property name="host" value="${mq.ip}" />
<property name="port" value="${mq.port}" />
<property name="virtualHost" value="${mq.virutalHost}" />
</bean>
<!--基于RabbitMQ连接工厂对象构建spring-rabbit的连接工厂对象Wrapper-->
<bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
<constructor-arg name="rabbitConnectionFactory" ref="rabbitMQConnectionFactory" />
</bean>
<!--构建RabbitAmdin对象,它负责创建Queue/Exchange/Bind对象-->
<bean id="rabbitAdmin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">
<constructor-arg name="connectionFactory" ref="connectionFactory" />
<property name="autoStartup" value="true"></property>
</bean>
<!--构建Rabbit Template对象,用于发送RabbitMQ消息,本程序使用它发送返回消息-->
<bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
<constructor-arg name="connectionFactory" ref="connectionFactory" />
</bean>
<!--RabbitMQ消息转化器,用于将RabbitMQ消息转换为AMQP消息,我们这里使用基本的Message Converter -->
<bean id="serializerMessageConverter"
class="org.springframework.amqp.support.converter.SimpleMessageConverter" />
<!--Message Properties转换器,用于在spring-amqp Message对象中的Message Properties和RabbitMQ的
Message Properties对象之间互相转换 -->
<bean id="messagePropertiesConverter"
class="org.springframework.amqp.rabbit.support.DefaultMessagePropertiesConverter" />
<!--定义AMQP Queue-->
<bean id="springMessageQueue" class="org.springframework.amqp.core.Queue">
<constructor-arg name="name" value="springMessageQueue" />
<constructor-arg name="autoDelete" value="false" />
<constructor-arg name="durable" value="true" />
<constructor-arg name="exclusive" value="false" />
<!--定义AMQP Queue创建所需的RabbitAdmin对象-->
<property name="adminsThatShouldDeclare" ref="rabbitAdmin" />
<!--判断是否需要在连接RabbitMQ后创建Queue-->
<property name="shouldDeclare" value="true" />
</bean>
<!--定义AMQP Exchange-->
<bean id="springMessageExchange" class="org.springframework.amqp.core.DirectExchange">
<constructor-arg name="name" value="springMessageExchange" />
<constructor-arg name="durable" value="true" />
<constructor-arg name="autoDelete" value="false" />
<!--定义AMQP Queue创建所需的RabbitAdmin对象-->
<property name="adminsThatShouldDeclare" ref="rabbitAdmin" />
<!--判断是否需要在连接RabbitMQ后创建Exchange-->
<property name="shouldDeclare" value="true" />
</bean>
<util:map id="emptyMap" map-class="java.util.HashMap" />
<!--创建Exchange和Queue之间的Bind-->
<bean id="springMessageBind" class="org.springframework.amqp.core.Binding">
<constructor-arg name="destination" value="springMessageQueue" />
<constructor-arg name="destinationType" value="QUEUE" />
<constructor-arg name="exchange" value="springMessageExchange" />
<constructor-arg name="routingKey" value="springMessage" />
<constructor-arg name="arguments" ref="emptyMap" />
</bean>
<!--侦听springMessageQueue队列消息的Message Listener-->
<bean id="consumerListener"
class="com.qf.rabbitmq.listener.RabbitMQConsumer" />
<!--创建侦听springMessageQueue队列的Message Listener Container-->
<bean id="messageListenerContainer"
class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="messageConverter" ref="serializerMessageConverter" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="messageListener" ref="consumerListener" />
<property name="queues" ref="springMessageQueue" />
<!--设置消息确认方式为自动确认-->
<property name="acknowledgeMode" value="AUTO" />
</bean>
</beans>