一. RabbitMQ基础知识
1.1 什么是RabbitMQ
是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。
1.2 AMQP协议
是具有现代特征的二进制协议,是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息中间件设计。
- Server:又称Broker,接受客户端的链接,实现AMQP的实体服务。
- Connection:链接,应用程序与Broker的网络连接。
- Channel:网络信道,几乎所有的操作的在Channel中进行,Channel是进行消息读写的通道。客户端可建立多个Channel,每个Channel代表以一个会话任务。
- Message: 消息,服务器和应用程序之间传送的数据,由Properties和Bady组成,Properties可以对消息进行修饰,比如消息的优先级,延迟等高级特性;Body则就是消息体内容。
- Publisher application和Consumer application相当于是两个系统
- Virtual host: 虚拟地址,用于进行逻辑隔离,最上层的消息路由。一个Virtual host里面可以由若干个exchange和queue,同一个Virtual host不能由同名的exchange和queue
- Exchange: 交换机,接收消息的,根据路由健转发消息到绑定的队列。
- Binding:Exchange和queue之间的虚拟连接,binding中包含routing key
- routing key:一个路由规则,虚拟机可用它来确定如何路由一个特定消息。
- Message Queue 消息队列,消息存放的路径,建议与Exchange是一对多的关系,一个exchange可以对应多个queue。
生产者生产消息流程
生产者将消息投递到X这个exchange上,exchange通过某种关系把消息路由到队列上,消费者通过监听队列,获取消息进行处理,一个队列可以跟多个交换机exchange,但是不建议这么做,因为这么做会提高代码的复杂度,建议一个队列对应一个交换机,同理一个消费者可以消费多个队列的消息,但是建议一个消费者就消费一个队列里的消息。
消费者消费流程
生产者产生一条消息,通过exchange路由到某个队列中,消费者通过监听队列,取消息进行消费。
二. RabbitMQ安装
- 首先在Linux上进行一些软件的准备工作,yum下来一些基础的软件包
yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz
- 下载RabbitMQ所需软件包(这里使用的是 RabbitMQ3.6.5 稳定版本,注意网站有时效性,如果下载不下来,可以评论告诉我,我给你发安装包)
wget www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-1.1.el7.lux.x86_64.rpm
wget www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm
- 安装服务命令
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm
rpm -ivh socat-1.7.3.2-1.1.el7.x86_64.rpm
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm
- 修改用户登录与连接心跳检测,注意修改
vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app
修改点1:loopback_users 中的 <<“guest”>>,只保留guest (用于用户登录)
修改点2:heartbeat 为10(用于心跳连接) - 首先启动服务(后面 | 包含了停止、查看状态以及重启的命令)
/etc/init.d/rabbitmq-server start | stop | status | restart
- 查看服务有没有启动:
rabbitmq-plugins enable rabbitmq_management
- 可查看管理端口有没有启动: lsof -i:5672 (5672是Rabbit的默认端口)
lsof -i:15672 或者 netstat -tnlp | grep 15672
- 一切OK 我们访问地址,输入用户名密码均为 guest :
http://你的ip地址:15672/
三. java集成RabbitMQ
- 引入pom文件,要和服务启保持一致
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.5</version>
</dependency>
- 生产者代码
package com.kingdee.rabbitmq.helloword;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
/**
* 生成者
*/
public class Sender {
public static void main(String[] args) throws Exception {
// 1 创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.10.139");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
// 2 创建Connection
Connection connection = connectionFactory.newConnection();
// 3 创建Channel
Channel channel = connection.createChannel();
// 4 声明
String queueName = "test001";
// 参数: queue名字,是否持久化,独占的queue(仅供此连接),不使用时是否自动删除, 其他参数
channel.queueDeclare(queueName, false, false, false, null);
Map<String, Object> headers = new HashMap<String, Object>();
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
//是否持久化
.deliveryMode(2)
.contentEncoding("UTF-8")
.headers(headers).build();
for(int i = 0; i < 5;i++) {
String msg = "Hello World RabbitMQ " + i;
channel.basicPublish("", queueName , props , msg.getBytes());
}
}
}
- 消费者代码
package com.kingdee.rabbitmq.helloword;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
/**
* 消费者
*/
public class Receiver {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory() ;
connectionFactory.setHost("192.168.10.139");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setAutomaticRecoveryEnabled(true);
connectionFactory.setNetworkRecoveryInterval(3000);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String queueName = "test001";
// durable 是否持久化消息
channel.queueDeclare(queueName, false, false, false, null);
QueueingConsumer consumer = new QueueingConsumer(channel);
// 参数:队列名称、是否自动ACK、Consumer
channel.basicConsume(queueName, true, consumer);
// 循环获取消息
while(true){
// 获取消息,如果没有消息,这一步将会一直阻塞
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("收到消息:" + msg);
}
}
}
四. RabbitMQ核心api
4.1 Exchange
接收消息,并根据路由键转发消息所绑定的队列
4.1.1 交换机Exchange属性
-
name:交换机名称
-
Type:交换机类型
-
Direct Exchange – 处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “dog”,则只有被标记为“dog”的消息才被转发,不会转发dog.puppy,也不会转发dog.guard,只会转发dog。
-
Topic Exchange – 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.” 只会匹配到“audit.irs”。
-
Fanout Exchange – 不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。
-
-
Durability: 是否需要持久化,True持久化
-
Auto Delete:当最后一个绑定到Exchange上的队列删除后,自动删除该Exchange
-
Internal: 当前exchange是否用于RabbitMQ内部使用,默认为false;
-
Arguments:扩展参数,用于扩展AMQP协议自制定化使用
参考资料:
https://www.cnblogs.com/ysocean/p/9251884.html