RabbitMQ简介
目前RabbitMQ是AMQP 0-9-1(高级消息队列协议)的一个实现,使用Erlang语言编写,利用了Erlang的分布式特性。
代码地址
http://download.csdn.net/download/qq_27116489/10131642
概念介绍:
- Broker:简单来说就是消息队列服务器实体。
- Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
- Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
- Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
- Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
- vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
- producer:消息生产者,就是投递消息的程序。
- consumer:消息消费者,就是接受消息的程序。
- channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
使用流程
AMQP模型中,消息在producer中产生,发送到MQ的exchange上,exchange根据配置的路由方式发到相应的Queue上,Queue又将消息发送给consumer,消息从queue到consumer有push和pull两种方式。 消息队列的使用过程大概如下:
- 客户端连接到消息队列服务器,打开一个channel。
- 客户端声明一个exchange,并设置相关属性。
- 客户端声明一个queue,并设置相关属性。
- 客户端使用routing key,在exchange和queue之间建立好绑定关系。
- 客户端投递消息到exchange。
exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。 exchange也有几个类型,完全根据key进行投递的叫做Direct交换机,例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。
Exchange类型
Exchange路由消息的集中类型:
名称 |
默认的预先定义exchange名字 |
作用描述 |
Direct exchange |
(Empty string) and amq.direct |
根据Binding指定的Routing Key,将符合Key的消息发送到Binding的Queue |
Fanout exchange |
amq.fanout |
将同一个message发送到所有同该Exchange bingding的queue |
Topic exchange |
amq.topic |
根据Binding指定的Routing Key,Exchange对key进行模式匹配后路由到相应的Queue,模式匹配时符号”#”匹配一个或多个词,符号”*”匹配正好一个词。 |
Headers exchange |
amq.match (and amq.headers in RabbitMQ) |
同direct exchange类似,不同之处是不再使用Routing Key路由,而是使用headers(message attributes)进行匹配路由到指定Queue。 |
Hello,Rabbitmq搭建
本文基于Spring rabbitmq搭建基础框架,
需要的依赖pom
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mq</groupId>
<artifactId>rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- <dependency> <groupId>com.rabbitmq</groupId> <artifactId>rabbitmq-client</artifactId>
<version>1.3.0</version> </dependency> -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-amqp</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
applicationcontext.xml
1,连接rabbitmq
<rabbit:connection-factory id="connectionFactory"
host="127.0.0.1" username="admin" password="admin" port="5672"
virtual-host="/" />
<!-- 连接配置 -->
<rabbit:admin connection-factory="connectionFactory" />
2,声明
<!-- spring template声明 -->
<rabbit:template exchange="test-mq-exchange" id="amqpTemplate"
connection-factory="connectionFactory" message-converter="messageConverter" />
<bean id="messageConverter"
class="org.springframework.amqp.support.converter.SimpleMessageConverter" />
3,队列
<!-- 标准的建立Queue的参数 -->
<rabbit:queue-arguments id="amqpQueueArguments">
<!-- 暂时没有 -->
</rabbit:queue-arguments>
<!-- queue -->
<rabbit:queue id="test_queue_key" name="test_queue_key" queue-arguments="amqpQueueArguments"
durable="true" auto-delete="false" exclusive="false" />
<rabbit:queue id="test_queue_key2" name="test_queue_key2" queue-arguments="amqpQueueArguments"
durable="true" auto-delete="false" exclusive="false" />
<rabbit:queue id="test_queue_key3" name="test_queue_key3" queue-arguments="amqpQueueArguments"
durable="true" auto-delete="false" exclusive="false" />
<!-- durable:是否持久化 exclusive: 仅创建者可以使用的私有队列,断开后自动删除 auto_delete: 当所有消费客户端连接断开后,是否自动删除队列 -->
4,交换器
<!-- exchange -->
<rabbit:direct-exchange name="test-mq-exchange"
durable="true" auto-delete="false" id="test-mq-exchange" auto-declare="true">
<rabbit:bindings>
<rabbit:binding queue="test_queue_key2" key="test_queue_key2" />
<rabbit:binding queue="test_queue_key" key="test_queue_key" />
<rabbit:binding queue="test_queue_key3" key="test_queue_key3" />
</rabbit:bindings>
</rabbit:direct-exchange>
5,监听消费者
<bean name="Consummer" class="com.mq.rabbitmq.Consummer" />
<bean name="Consummer2" class="com.mq.rabbitmq.Consummer" />
<bean name="Consummer3" class="com.mq.rabbitmq.Consummer" />
<!-- 配置监听 消费者 -->
<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="auto">
<!-- queues 监听队列,多个用逗号分隔 ref 监听器 -->
<rabbit:listener queues="test_queue_key2" ref="Consummer2" />
<rabbit:listener queues="test_queue_key" ref="Consummer" />
<rabbit:listener queues="test_queue_key3" ref="Consummer3" />
</rabbit:listener-container>
6,Spring包扫描
<context:component-scan base-package="com.mq.rabbitmq"></context:component-scan>
完整的applicationcontext.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans default-lazy-init="false" xmlns:p="http://www.springframework.org/schema/p"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
xmlns:rabbit="http://www.springframework.org/schema/rabbit" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd ">
<rabbit:connection-factory id="connectionFactory"
host="127.0.0.1" username="admin" password="admin" port="5672"
virtual-host="/" />
<!-- 连接配置 -->
<rabbit:admin connection-factory="connectionFactory" />
<!-- spring template声明 -->
<rabbit:template exchange="test-mq-exchange" id="amqpTemplate"
connection-factory="connectionFactory" message-converter="messageConverter" />
<bean id="messageConverter"
class="org.springframework.amqp.support.converter.SimpleMessageConverter" />
<!-- 标准的建立Queue的参数 -->
<rabbit:queue-arguments id="amqpQueueArguments">
<!-- 暂时没有 -->
</rabbit:queue-arguments>
<!-- queue -->
<rabbit:queue id="test_queue_key" name="test_queue_key" queue-arguments="amqpQueueArguments"
durable="true" auto-delete="false" exclusive="false" />
<rabbit:queue id="test_queue_key2" name="test_queue_key2" queue-arguments="amqpQueueArguments"
durable="true" auto-delete="false" exclusive="false" />
<rabbit:queue id="test_queue_key3" name="test_queue_key3" queue-arguments="amqpQueueArguments"
durable="true" auto-delete="false" exclusive="false" />
<!-- durable:是否持久化 exclusive: 仅创建者可以使用的私有队列,断开后自动删除 auto_delete: 当所有消费客户端连接断开后,是否自动删除队列 -->
<!-- exchange -->
<rabbit:direct-exchange name="test-mq-exchange"
durable="true" auto-delete="false" id="test-mq-exchange" auto-declare="true">
<rabbit:bindings>
<rabbit:binding queue="test_queue_key2" key="test_queue_key2" />
<rabbit:binding queue="test_queue_key" key="test_queue_key" />
<rabbit:binding queue="test_queue_key3" key="test_queue_key3" />
</rabbit:bindings>
</rabbit:direct-exchange>
<bean name="Consummer" class="com.mq.rabbitmq.Consummer" />
<bean name="Consummer2" class="com.mq.rabbitmq.Consummer" />
<bean name="Consummer3" class="com.mq.rabbitmq.Consummer" />
<!-- 配置监听 消费者 -->
<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="auto">
<!-- queues 监听队列,多个用逗号分隔 ref 监听器 -->
<rabbit:listener queues="test_queue_key2" ref="Consummer2" />
<rabbit:listener queues="test_queue_key" ref="Consummer" />
<rabbit:listener queues="test_queue_key3" ref="Consummer3" />
</rabbit:listener-container>
<context:component-scan base-package="com.mq.rabbitmq"></context:component-scan>
</beans>
生产者
发送消息接口
package com.mq.rabbitmq;
public interface MqInt {
public void sendDataToQueue(String queueKey, Object object);
}
接口实现类
package com.mq.rabbitmq;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MqImpl implements MqInt {
@Autowired
private AmqpTemplate amqpTemplate;
@Override
public void sendDataToQueue(String queueKey, Object object) {
amqpTemplate.convertAndSend(queueKey, object);
}
}
监听 ------消费者
package com.mq.rabbitmq;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
public class Consummer implements MessageListener{
@Autowired
private AmqpTemplate amqpTemplate;
public int count =1;
@Override
public void onMessage(Message message) {
System.out.println(count+"-----------");
count++;
System.out.println(message);
}
}
测试类
package test;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mq.rabbitmq.MqImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationcontext.xml" })
public class TestQueue {
@Autowired
MqImpl mqImpl;
final String queue_key = "test_queue_key";
final String queue_key2 = "test_queue_key2";
final String queue_key3 = "test_queue_key3";
@Test
public void send() {
Map<String, String> msg = new HashMap<String, String>();
msg.put("data", "hello,rabbmitmq!");
System.out.println("--+amqpTemplate");
for (int i = 0; i < 200; i++) {
mqImpl.sendDataToQueue(queue_key, msg);
}
System.out.println("------------------");
}
}
可以登录localhost:5672/看交换器和queue的效果