实际上,AMQP具有多项JMS所不具备的优势。首先,AMQP为消息定义了线路层的协议。AMQP在互相协作方面就要优于JMS—它不仅能跨不同的AMQP实现,还能跨语言和平台。AMQP能够不局限于java平台和语言。
1. AMQP简介
在JMS消息中主要有三个参与者:消息的生产者,消息的消费者以及消费者和生产者之间传递的通道。在JMS中,通道有助于解耦消息的生产者和消费者,但是这两者依然会与通道相耦合。
在使用AMQP的生产者并不会直接将消息发不到队列中。AMQP在消息的生产者以及传递消息的队列之间引入了一种间接的机制:Exchange。这样,消息的生产者将消息发不到一个Exchange。Exchange会绑定到一个或者多个队列上,他负责将消息路由到队列上。
Exchange不是简单的消息传递到队列中,并不仅仅是一种穿透机制。AMQP定义了四种不同类型的Exchange,每一种都有不同的路由算法。
四种标准的AMQP Exchange如下所示:
- Direct:如果消息routing key 与 binding的routing key直接匹配,消息将会路由到该队列上;
- Topic:如果消息的routing key 与binding的routing key 符合通配符匹配的话,将会把消息路由到队列上;
- Headers:如果消息参数列表中的头消息和值都与binding参数表中相匹配,消息将会路由到队列上,
- Feanout:不管消息的routing key 和参数的头信息是什么,消息将会路由到所有队列上。
借助于这四种类型的Exchange,很容易就能定义任意数量的路由模式。而不是仅仅局限于点对点和发布—订阅的模式。
2. 配置Spring支持AMQP消息
RabbitMQ是一个流行的开源消息代理,它实现了AMQP。Spring AMQP为 RabbitMQ提供了支持,包括 RabbitMQ链接工厂,模板以及Spring配置命名空间。
配置RabbitMQ连接工厂—通过Spring命名空间方式
配置连接工厂
<connection-factory id="connectionFactroy"/>
默认情况下链接工厂有一个默认的localhost的5672端口,用户名和密码均为 guest。在开发环境中这样配置没有问题但对于生产环境我们需要修改这些默认值。
<connection-factory id="connectionFactroy"
host="${rabbitmq.host}"
port="${rabbitmq.port}"
username="${rabbitmq.username}"
password="${rabbitmq.password}"
/>
3.声明队列,Exchange以及binding
//声明一个简单的队列
<admin connection-factroy="connectionFactroy"/>
<queue id="aplittle" name="spittle.alert"/>
//声明一个复杂的队列
<admin connection-factroy="connectionFactroy"/>
<queue name="spittle.alert.queue.1">
<queue name="spittle.alert.queue.2">
<queue name="spittle.alert.queue.3">
<fanout-exchange name="splittle.fanout">
<bindings>
<binding queue="spittle.alert.queue.1"/>
<binding queue="spittle.alert.queue.2"/>
<binding queue="spittle.alert.queue.3"/>
</bindings>
</fanout-exchange>
4. 使用RabbitTemplate发送消息
//配置RabbitTemplate命名空间
<template id="rabbitTemplate" connection-factroy="connectionFactroy"/>
//使用使用RabbitTemplate发送消息
public class AlertServiceImpl implements AlertService{
private RabbitTemplate rabbit;
@Autowired
public AlertServiceImpl(RabbitTemplate rabbit){
this.rabbit=rabbit;
}
public void sendSpittleAlert(Spittle spittle){
//1Exchange的名称,2routing key,3要发送的对象
rabbit.convertAndSend("xxx","xxx","xxx");
}
}
5. 使用RabbitTemplate接收消息
共有两种方式接收消息,分别为使用RabbitTemplate同步的从队列中获取消息。还有使用定义消息驱动的AMQP POJO获取消息。
//RabbitTemplate同步获取消息
<templeate id="rabbitTemplate"
connection-factory="connectionFactory"
exchange="spittle.alert.exchange"
routing-key="spittle-alerts"
queue="spittle.alert.queue" />
Message msg = rabbit.receive();
//定义消息驱动的AMQP POJO获取消息
public class SpittleAlertHandler{
public void handleSpittleAlert(Spittle spittle){
//....implementation goes here....
}
}
//配置spring上下文监听
<bean id="spittleListener"
class="com.xxx.xxx.xxx.SpittleAlertHandler"/>
//声明一个监听容器和监听器,当消息到达时调用SpittleAlertHandler
<listener-container connection-factory="connectionFactory">
<listener ref="spittleListener"
method="handleSpittleAlert"
queue-names="spittle.alert.queue">
</listener>
</listener-container>