RabbitMQ-简介及安装测试(一)
一、基本简介
RabbitMQ 的优点
- 基于 ErLang 语言开发具有高可用高并发的优点,适合集群服务器
- 健壮、稳定、易用、跨平台、支持多种语言、文档齐全
- 有消息确认机制和持久化机制,可靠性高
- 开源
RabbitMQ 的概念
生产者和消费者
- Producer:消息的生产者
- Consumer:消息的消费者
Queue
- 消息队列,提供了 FIFO 的处理机制,具有缓存消息的能力。RabbitMQ 中,队列消息可以设置为持久化,临时或者自动删除。
- 设置为持久化的队列,Queue 中的消息会在 Server 本地硬盘存储一份,防止系统 Crash,数据丢失
- 设置为临时队列,Queue 中的数据在系统重启之后就会丢失
- 设置为自动删除的队列,当不存在用户连接到 Server,队列中的数据会被自动删除
ExChange
Exchange
类似于数据通信网络中的交换机,提供消息路由策略。RabbitMQ
中,Producer
不是通过信道直接将消息发送给Queue
,而是先发送给ExChange
。一个ExChange
可以和多个Queue
进行绑定,Producer
在传递消息的时候,会传递一个ROUTING_KEY
,ExChange
会根据这个ROUTING_KEY
按照特定的路由算法,将消息路由给指定的Queue
。和Queue
一样,ExChange
也可设置为持久化,临时或者自动删除
ExChange 的 4 种类型
- direct(默认):直接交换器,工作方式类似于单播,ExChange 会将消息发送完全匹配 ROUTING_KEY 的 Queue(key 就等于 queue)
- fanout:广播式交换器,不管消息的 ROUTING_KEY 设置为什么,ExChange 都会将消息转发给所有绑定的 Queue(无视 key,给所有的 queue 都来一份)
- topic:主题交换器,工作方式类似于组播,ExChange 会将消息转发和 ROUTING_KEY 匹配模式相同的所有队列(key 可以用“宽字符”模糊匹配 queue),比如,ROUTING_KEY 为
user.stock
的 Message 会转发给绑定匹配模式为* .stock,user.stock
,* . *
和#.user.stock.#
的队列。( * 表是匹配一个任意词组,# 表示匹配 0 个或多个词组) - headers:消息体的 header 匹配,无视 key,通过查看消息的头部元数据来决定发给那个 queue(AMQP 头部元数据非常丰富而且可以自定义)
Binding
所谓绑定就是将一个特定的
ExChange
和一个特定的Queue
绑定起来。ExChange
和Queue
的绑定可以是多对多的关系
Virtual Host
在
RabbitMQ Server
上可以创建多个虚拟的Message Broker
,又叫做Virtual Hosts (vhosts)
。每一个 vhost 本质上是一个mini-rabbitmq server
,分别管理各自的ExChange
,和bindings
。vhost
相当于物理的Server
,可以为不同 app 提供边界隔离,使得应用安全的运行在不同的 vhost 实例上,相互之间不会干扰。Producer 和 Consumer 连接 rabbit server 需要指定一个 vhost
RabbitMQ 的使用过程
- 客户端连接到消息队列服务器,打开一个 Channel。
- 客户端声明一个 ExChange,并设置相关属性。
- 客户端声明一个 Queue,并设置相关属性。
- 客户端使用 Routing Key,在 ExChange 和 Queue 之间建立好绑定关系。
- 客户端投递消息到 ExChange。
- ExChange 接收到消息后,就根据消息的 key 和已经设置的 binding,进行消息路由,将消息投递到一个或多个队列里
二、安装
基于docker安装
docker-compose.yml
version: '3.1'
services:
rabbitmq:
restart: always
image: rabbitmq:management
container_name: rabbitmq
ports:
- 5672:5672
- 15672:15672
environment:
TZ: Asia/Shanghai
RABBITMQ_DEFAULT_USER: rabbit
RABBITMQ_DEFAULT_PASS: 123456
volumes:
- ./data:/var/lib/rabbitmq
docker-compose up -d
访问浏览器:http://ip:15672,出现以下界面表示安装成功,登录账户为RABBITMQ_DEFAULT_USER、RABBITMQ_DEFAULT_PASS设置的
三、使用
普通maven 导入依赖
<dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.5.1</version> </dependency>
springboot整合RabbitMQ
- 依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> <version>2.1.4.RELEASE</version> </dependency>
- 配置文件
spring: application: name: spring-boot-amqp rabbitmq: host: 192.168.232.119 port: 5672 username: rabbit password: 123456
创建虚拟主机
设置用户,分配虚拟主机
测试
为了测试方便代码复用这里封装了一个简单的连接mq的工具类
import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @ClassName RabbitMqUtil * @Author ZC * @Date 2022/7/2 21:21 * @Version 1.0 * @Description */ public class RabbitMqUtil { private final String host = "192.168.232.119"; private final int port = 5672; private final String username = "test"; private final String password = "test12"; private final String virtualHost = "test_mq"; /** * 连接RabbitMq * @return * @throws IOException * @throws TimeoutException */ public Connection getConnection() throws IOException, TimeoutException { //连接Mq服务器、主机、端口、用户名、密码 ConnectionFactory factory = new ConnectionFactory(); factory.setHost(host); factory.setPort(port); factory.setUsername(username); factory.setPassword(password); //设置虚拟主机 factory.setVirtualHost(virtualHost); Connection connection = factory.newConnection(); return connection; } }
提供者
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import org.example.utils.RabbitMqUtil;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @ClassName SimpleProvider
* @Author ZC
* @Date 2022/7/2 21:33
* @Version 1.0
* @Description 消息提供者
*/
public class SimpleProvider {
private final static String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
RabbitMqUtil rabbitMqUtil = new RabbitMqUtil();
//1、连接mq服务
Connection connection = rabbitMqUtil.getConnection();
//2、通过连接对象获得一个连接通道
Channel channel = connection.createChannel();
//3、声明队列
/**
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
* Map<String, Object> arguments)
* queue: 队列名称
* durable: 是否持久化(即服务重启时是否还存在)
* exclusive: 是否独占(即当前队列是否只被这一个队列消费)
* autoDelete: 是否自动删除(即当该队列没有被连接使用后是否删除)
* arguments: 队列其他参数的设置
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//4、发送信息到mq
String message = "hello rabbitMq";
/**
* basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
* exchange:交换机
* routingKey: 如果交换机是默认交换机那么这个相当于队列名称
* props:消息相关参数信息
* body: 具体消息
*/
channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
System.out.println("send: message<"+message+">发送成功");
}
}
消费者
package org.example.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import org.example.utils.RabbitMqUtil;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @ClassName SimpleConsumer
* @Author ZC
* @Date 2022/7/2 22:02
* @Version 1.0
* @Description
*/
public class SimpleConsumer {
private final static String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//1、获取连接
Connection connection = new RabbitMqUtil().getConnection();
//2、获取一个连接通道
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//3、获取队列中的消息
//3。1、处理消息-回调之后使用
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
//监听队列
/**
* basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback)
*
* queue: 队列名称
* autoAck:
* deliverCallback: 消息传递时回调
* cancelCallback: 消费者取消时回调
*/
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
//非lambada表达式接收消息
// Consumer consumer = new DefaultConsumer(channel){
// public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// String message = new String(body,"utf-8");
// System.out.println(" [x] Received '" + message + "'");
// }
// };
// //监听队列
// channel.basicConsume(QUEUE_NAME,true,consumer);
}
}