RabbitMQ-简介及安装测试(一)

一、基本简介

RabbitMQ 的优点

  • 基于 ErLang 语言开发具有高可用高并发的优点,适合集群服务器
  • 健壮、稳定、易用、跨平台、支持多种语言、文档齐全
  • 有消息确认机制和持久化机制,可靠性高
  • 开源

RabbitMQ 的概念

生产者和消费者

  • Producer:消息的生产者
  • Consumer:消息的消费者

Queue

  • 消息队列,提供了 FIFO 的处理机制,具有缓存消息的能力。RabbitMQ 中,队列消息可以设置为持久化,临时或者自动删除。
  • 设置为持久化的队列,Queue 中的消息会在 Server 本地硬盘存储一份,防止系统 Crash,数据丢失
  • 设置为临时队列,Queue 中的数据在系统重启之后就会丢失
  • 设置为自动删除的队列,当不存在用户连接到 Server,队列中的数据会被自动删除

ExChange

Exchange 类似于数据通信网络中的交换机,提供消息路由策略。RabbitMQ 中,Producer 不是通过信道直接将消息发送给 Queue,而是先发送给 ExChange。一个 ExChange 可以和多个 Queue 进行绑定,Producer 在传递消息的时候,会传递一个 ROUTING_KEYExChange 会根据这个 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,和 bindingsvhost 相当于物理的 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);
    }
}

posted @ 2022-07-03 00:20  胡同咖啡  阅读(160)  评论(0编辑  收藏  举报