订阅者模块

1. 客户端实现思路

在 RabbitMQ 中,提供服务的是信道,因此在客户端的实现中,弱化了 Client 客户端的概念,也就是说在 RabbitMQ 中并不会向用户展示网络通信的概念出来,而是以一种提供服务的形式来体现。

其实现思想类似于普通的功能接口封装,一个接口实现一个功能,接口内部完成向客户端请求的过程,但是对外并不需要体现出客户端与服务端通信的概念,用户需要什么服务就调用什么接口就行。

基于以上的思想,客户端的实现共分为四大模块:

  • 订阅者模块:
    • 一个并不直接对用户展示的模块,其在客户端体现的作用就是对于角色的描 述,表示这是一个消费者
  • 信道模块
    • 一个直接面向用户的模块,内部包含多个向外提供的服务接口,用户需要什么服务,调用对应接口即可○ 其包含交换机声明/删除,队列声明/删除,绑定/解绑,消息发布/确认,订阅/解除订阅等服务。
  • 连接模块
    • 这是唯一能体现出网络通信概念的一个模块了,它向用户提供的功能就是用于打开/关闭信道。
  • 异步线程模块
    • 虽然客户端部分,并不对外体现网络通信的概念,但是本质上内部还是包含有网络通信的,因此既然有网络通信,那么就必须包含有一个网络通信 IO 事件监控线程模块,用于进行客户端连接的 IO 事件监控,以便于在事件出发后进行 IO 操作。
    • 其次,在客户端部分存在一个情况就是,当一个信道作为消费者而存在的时 候,服务端会向信道推送消息,而用户这边需要对收到的消息进行不同的业务处理,而这个消息的处理需要一个异步的工作线程池来完成。
    • 因此异步线程模块包含两个部分:
      • 客户端连接的 IO 事件监控线程
      • 推送过来的消息异步处理线程

基于以上模块,实现一个客户端的流程也就比较简单了

  1. 实例化异步线程对象
  2. 实例化连接对象
  3. 通过连接对象,创建信道
  4. 根据信道获取自己所需服务
  5. 关闭信道
  6. 关闭连接

2. 订阅者模块

与服务端,并无太大差别,客户端这边虽然订阅者的存在感微弱了很多,但是还是有的,当进行队列消息订阅的时候,会伴随着一个订阅者对象的创建,而这个订阅者对象有以下几个作用:

  • 描述当前信道订阅了哪个队列的消息。
  • 描述了收到消息后该如何对这条消息进行处理。
  • 描述收到消息后是否需要进行确认回复。

所以,订阅者模块并不直接对用户展示,它是对消费者角色的描述。当用户通过信道订阅队列时,内部会创建一个订阅者对象,该对象负责处理从服务端推送过来的消息。

设计要点:

  1. 每个订阅者对应一个消费者标签(consumer_tag)和一个队列(queue_name)。
  2. 订阅者需要提供一个回调函数,当消息到达时,异步线程模块会调用这个回调函数。
  3. 订阅者可能支持自动确认或手动确认模式。

因此订阅者信息:

  • 订阅者标识
  • 订阅队列名
  • 是否自动确认标志
  • 回调处理函数(收到消息后该如何处理的回调函数对象)
cpp 复制代码
#ifndef __M_CONSUMER_H__
#define __M_CONSUMER_H__
#include "../mqcommon/logger.hpp"
#include "../mqcommon/helper.hpp"
#include "../mqcommon/msg.pb.h"
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <vector>
#include <functional>


namespace rabbitmq
{
    using ConsumerCallback = std::function<void(const std::string, const BasicProperties *bp, const std::string)>;
    struct Consumer
    {
        using ptr = std::shared_ptr<Consumer>;
        std::string _tag; //消费者标识
        std::string _qname; //消费者订阅的队列名称
        bool _auto_ack; //自动确认标志
        ConsumerCallback _callback;

        Consumer()
        {
            DLOG("new Consumer: %p", this);
        }
        Consumer(const std::string &ctag, const std::string &queue_name,  bool ack_flag, const ConsumerCallback &cb)
            :_tag(ctag), _qname(queue_name), _auto_ack(ack_flag), _callback(std::move(cb)) 
        {
            DLOG("new Consumer: %p", this);
        }
        ~Consumer() 
        {
            DLOG("del Consumer: %p", this);
        }
    };
}

#endif
相关推荐
fchampion1 天前
最终一致性
java·spring·rabbitmq·github·mvc
予枫的编程笔记2 天前
【Kafka基础篇】RabbitMQ、RocketMQ、Kafka怎么选?3种主流MQ核心差异实测解析
kafka·rabbitmq·rocketmq·分布式流处理·发布订阅模型·消息队列(mq)·点对点模型
Ronin3052 天前
连接管理模块和服务器模块
服务器·rabbitmq·网络通信·tcp连接
Jinkxs4 天前
RabbitMQ - 第一个 Hello World 程序:SpringBoot 版极简集成
spring boot·rabbitmq·java-rabbitmq
希忘auto4 天前
详解RabbitMQ高级特性之延迟队列
rabbitmq
Ronin3055 天前
信道管理模块
网络·rabbitmq·网络通信
马猴烧酒.6 天前
【面试八股|RabbitMQ】RabbitMQ常见面试题详解笔记
笔记·面试·rabbitmq
XP62267 天前
Linux安装RabbitMQ
linux·运维·rabbitmq
PD我是你的真爱粉7 天前
RabbitMQ架构实战2️⃣:分布式事务下的跨服务数据同步
分布式·架构·rabbitmq