项目实战之RabbitMQ冗余双写架构

🧑‍💻作者名称:DaenCode
🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。
😎人生感悟:尝尽人生百味,方知世间冷暖。
📖所属专栏:项目所感所想


在这里插入图片描述


文章目录

  • 🌟架构图
  • 🌟application.properties
  • 🌟RabbitMQ配置
  • 🌟消息协议封装
  • 🌟消息类型封装
  • 🌟C端消费者
  • 🌟B端消费者
  • 🌟发送消息与处理消息
  • 🌟最后

🌟架构图

在这里插入图片描述

🌟application.properties

redundancy.mq.redundancy-event-exchange=redundancy.event.exchange
redundancy.mq.add-routing-key=redundancy.add.business.consumer.routing.key
redundancy.mq.add-business-binding-key=redundancy.add.business.*.routing.key
redundancy.mq.add-consumer-binding-key=redundancy.add.*.consumer.routing.key
redundancy.mq.add-business-queue=redundancy.add.business.queue
redundancy.mq.add-consumer-queue=redundancy.add.consumer.queue

🌟RabbitMQ配置

package top.daencode.config;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Copyright (C) 2023-11-29  智源恩创网络科技工作室
 *
 * @BelongsProject: architecture-solution
 * @BelongsPackage: top.daencode.mq
 * @author: DaenCode
 * @createTime: 2023-11-29  15:08
 * @description: TODO
 * @version: 1.0
 */
@Configuration
@Slf4j
@Data
@ConfigurationProperties(prefix = "redundancy.mq")
public class RabbitMqForRedundancyConfig {
    /**
     * 交换机
     */
    private String redundancyEventExchange;
    /**
     * 添加路由key
     */
    private String addRoutingkey;
    /**
     * B端添加绑定key
     */
    private String addBusinessBindingKey;
    /**
     * C端添加绑定key
     */
    private String addConsumerBindingKey;
    /**
     * B端添加队列
     */
    private String addBusinessQueue;
    /**
     * C端添加队列
     */
    private String addConsumerQueue;

    /**
     * 创建冗余双写交换机
     * @return
     */
    @Bean
    public Exchange redundancyEventExchange(){
        return new TopicExchange(redundancyEventExchange);
    }

    /**
     * 创建B端添加队列
     * @return
     */
    @Bean
    public Queue addBusinessQueue(){
        return new Queue(addBusinessQueue,true,false,false);
    }

    /**
     * 创建C端添加队列
     * @return
     */
    @Bean
    public Queue addConsumerQueue(){
        return new Queue(addConsumerQueue,true,false,false);
    }
    /**
     * B端绑定关系
     */
    @Bean
    public Binding addBusinessBinding(){
        return new Binding(addBusinessQueue, Binding.DestinationType.QUEUE,redundancyEventExchange,
                addBusinessBindingKey,null);
    }

    /**
     * C端交换机绑定到队列
     * @return
     */
    @Bean
    public Binding addConsumerBinding(){
        return new Binding(addConsumerQueue, Binding.DestinationType.QUEUE,redundancyEventExchange,
                addConsumerBindingKey,null);
    }
}

🌟消息协议封装

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventMessage implements Serializable {
    /**
     * 消息队列id
     */
    private String messageId;

    /**
     * 事件类型
     */
    private String eventMessageType;

    /**
     * 业务id
     */
    private String bizId;

    /**
     * 消息体
     */
    private String content;

    /**
     * 异常备注
     */
    private String remark;
}

🌟消息类型封装

public enum EventMessageTypeEnum {
    REDUNDANCY_ADD,
    REDUNDANCY_ADD_BUSINESS,
    REDUNDANCY_ADD_CONSUMER,
    REDUNDANCY_DEL,
    REDUNDANCY_DEL_BUSINESS,
    REDUNDANCY_DEL_CONSUMER,
    REDUNDANCY_UPDATE,
    REDUNDANCY_UPDATE_BUSINESS,
    REDUNDANCY_UPDATE_CONSUMER,
}

🌟C端消费者

@Component
@Slf4j
@RabbitListener(queuesToDeclare = {@Queue("redundancy.add.consumer.queue")})
public class RedundancyAddConsumerMQListener {
    @Autowired
    private DetailService detailService;
    /**
     * 消费消息
     * @param eventMessage
     * @param message
     * @param channel
     */
    @RabbitHandler
    public void handleAddConsumer(EventMessage eventMessage, Message message, Channel channel){
        try {
            eventMessage.setEventMessageType(EventMessageTypeEnum.REDUNDANCY_ADD_CONSUMER.name());
            boolean flag= detailService.handleAddDetail(eventMessage);
        } catch (Exception e) {
            log.error("handleAddConsumer--消费失败{}",eventMessage);
        }
    }
}

🌟B端消费者

@Component
@Slf4j
@RabbitListener(queuesToDeclare = {@Queue("redundancy.add.business.queue")})
public class RedundancyAddBusinessMQListener {
    @Autowired
    private DetailService detailService;
    /**
     * 消费消息
     * @param eventMessage
     * @param message
     * @param channel
     */
    @RabbitHandler
    public void handleAddBusiness(EventMessage eventMessage, Message message, Channel channel){
        try {
            eventMessage.setEventMessageType(EventMessageTypeEnum.REDUNDANCY_ADD_BUSINESS.name());
            boolean flag= detailService.handleAddDetail(eventMessage);
        } catch (Exception e) {
            log.error("handleAddBusiness--消费失败{}",eventMessage);
        }
    }
}

🌟发送消息与处理消息

   /**
     * 发送新增消息
     * @param detailRequest
     */
    @Override
    public void addDetail(DetailRequest detailRequest) {
        detailRequest.setBId(IDUtil.generateRandomNumber(5));
        detailRequest.setCId(IDUtil.generateRandomNumber(5));
        //构造消息
        EventMessage eventMessage = EventMessage.builder()
                .messageId(IDUtil.generateRandomNumber(5).toString())
                .content(JsonUtil.obj2Json(detailRequest))
                .eventMessageType(EventMessageTypeEnum.REDUNDANCY_ADD.name())
                .build();
        rabbitTemplate.convertAndSend(rabbitMqForRedundancyConfig.getRedundancyEventExchange(),
                rabbitMqForRedundancyConfig.getAddRoutingkey(),eventMessage);
    }
//处理新增消息
@Override
    public boolean handleAddDetail(EventMessage eventMessage) {
        String messageType= eventMessage.getEventMessageType();
        DetailRequest detailRequest=JsonUtil.json2Obj(eventMessage.getContent(), DetailRequest.class);
        if (messageType.equals(EventMessageTypeEnum.REDUNDANCY_ADD_CONSUMER.name())){
            CDetailDO cDetailDOIndb=cDetailMapper.selectOne(new QueryWrapper<CDetailDO>()
                    .eq("c_id",detailRequest.getCId())
                    .eq("detail",detailRequest.getDetail()));
            if (cDetailDOIndb==null){
                CDetailDO cDetailDO = CDetailDO.builder()
                        .bId(detailRequest.getBId())
                        .cId(detailRequest.getCId())
                        .detail(detailRequest.getDetail())
                        .build();
                cDetailMapper.insert(cDetailDO);
            }else {
                log.error("handleAddDetail---REDUNDANCY_ADD_CONSUMER重复{}",eventMessage);
            }
        } else if (messageType.equals(EventMessageTypeEnum.REDUNDANCY_ADD_BUSINESS.name())) {
            BDetailDO bDetailDOIndb=bDetailMapper.selectOne(new QueryWrapper<BDetailDO>()
                    .eq("b_id",detailRequest.getCId())
                    .eq("detail",detailRequest.getDetail()));
            if (bDetailDOIndb==null){
                BDetailDO bDetailDO = BDetailDO.builder()
                        .bId(detailRequest.getBId())
                        .cId(detailRequest.getCId())
                        .detail(detailRequest.getDetail())
                        .build();
                bDetailMapper.insert(bDetailDO);
            }else {
                log.error("handleAddDetail---REDUNDANCY_ADD_BUSINESS重复{}",eventMessage);
            }
        }
        return false;
    }

🌟最后

最后,感谢大家对本文的阅读,希望对大家有帮助。


请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/207086.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv7全网独家首发改进:SENet v2,Squeeze-Excitation模块融合Dense Layer,效果秒杀SENet

💡💡💡本文自研创新改进:SENet v2,针对SENet主要优化点,提出新颖的多分支Dense Layer,并与Squeeze-Excitation网络模块高效融合,融合增强了网络捕获通道模式和全局知识的能力 推荐指数:五星 收录 YOLOv7原创自研 https://blog.csdn.net/m0_63774211/category_12…

【localhost refused to connect】解决 linux服务器启动 jupyter notebook 后本地浏览器打不开

问题描述 在linux上输入&#xff1a; jupyter notebook 命令后&#xff0c;弹出的火狐浏览器可以打开笔记本&#xff0c;但是复制它给的加密 url 到 Google 或者 Edge 浏览器都出现如下情况&#xff1a; 解决办法 1. 生成 jupyter notebook 配置文件 在 linux 命令行输入如下…

2023年小美赛认证杯A题太阳黑子预测(Sunspot Forecasting)思路模型代码解析

2023年小美赛认证杯A题&#xff1a;太阳黑子预测&#xff08;Sunspot Forecasting&#xff09; 【请电脑打开本文链接&#xff0c;扫描下方名片中二维码&#xff0c;获取更多资料】 一、问题重述 太阳黑子是太阳光球上的现象&#xff0c;呈暂时性斑点&#xff0c;比周围区域…

Xilinx FPGA——ISE的UCF时序约束

时序约束是我们对FPGA设计的要求和期望&#xff0c;例如&#xff0c;我们希望FPGA设计可以工作在多快的时钟频率下等等。 设计是要求系统中的每一个时钟都进行时序约束。 一、分组约束语法&#xff08;NET、PIN、INST&#xff09; TNM是最基本的分组约束语法&#xff0c;其语法…

ubuntu/vscode下的c/c++开发之-CMake语法与练习

Cmake学习 1 语法特性介绍 基本语法格式&#xff1a;指令(参数 1 参数 2...) 参数使用括弧括起参数之间使用空格或分号分开 指令是大小写无关的&#xff0c;参数和变量是大小写相关的 set(HELLO hello.cpp) add_executable(hello main.cpp hello.cpp) ADD_EXECUTABLE(hello ma…

spring-cloud-alibaba 官方版本说明

版本说明 alibaba/spring-cloud-alibaba Wiki GitHub 云原生应用脚手架 构建方式&#xff1a;maven 语言&#xff1a;java springboot 2.7.6 架构&#xff1a;单模块&#xff0c;mvc 架构 下面是脚手架生成。。。。。。。。。。。。。。。。。。。 单模块pom mvc 代码…

关于PFMEA的风险评估都在这里——SunFMEA软件

1、评价严重度 严重度应该独立于发生度和探测度的评价&#xff0c;不能认为发生概率低或者探测能力强&#xff0c;失效就不会到达顾客手中&#xff0c;不会造成糟糕的失效影响&#xff0c;严重度就低。 其实&#xff0c;严重度评估的是已经识别的失效链的严重程度&#xff0c…

Oracle忘记所有密码怎么办

最近遇到一个Oracle的问题&#xff0c;密码要过期了&#xff0c;但是除了用户密码&#xff0c;其他密码都不知道了&#xff0c;修改不了密码怎么办呢&#xff1f; 试了各种方法&#xff0c;最终下面的方式生效了&#xff1a; 首先&#xff0c;使用orapwd生成新的密码文件&…

六、三台主机免密登录和时钟同步

目录 1、免密登录 1.1 为什么要免密登录 1.2 免密 SSH 登录的原理

CSS 在性能优化方面的实践

前言 CSS&#xff08;层叠样式表&#xff09;是一种用于描述网页外观和格式的语言。随着网页变得越来越复杂&#xff0c;CSS文件的大小也随之增加&#xff0c;这可能会对网页性能产生负面 .box {width: 100px;height: 100px;transition: transform 0.3s; }.box:hover {transf…

Java全栈基础篇--集合

集合 集合&#xff1a;集合是java中提供的一种容器&#xff0c;可以用来存储多个数据。 特点&#xff1a; 长度不固定&#xff0c;还可以存储不同的数据&#xff08;但是一般都用同一类型&#xff09; 集合和数组既然都是容器&#xff0c;它们有啥区别呢&#xff1f; 数组的长…

数据可视化工具APITable:实现强大的多维表格功能并随时随地远程访问

APITable免费开源的多维表格与可视化数据库公网远程访问 文章目录 APITable免费开源的多维表格与可视化数据库公网远程访问前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c…

血的教训---入侵redis并免密登录redis所在服务器漏洞复现

血的教训—入侵redis并免密登录redis所在服务器漏洞复现 今天就跟着我一起来入侵redis并免密登录redis所在服务器吧&#xff0c;废话不多说&#xff0c;我们直接开始吧。 这是一个体系的学习步骤&#xff0c;当然如果基础扎实的话可以继续往下面看 以下都是关联的文章&#xff…

算法与数据结构有区别吗?

算法和数据结构并不是同一件事。严格来说&#xff0c;它们并不是等效的。但是&#xff0c;我们通常在使用的时候会互换这两个术语。为了简便&#xff0c;后文我们会用数据结构这个术语来指代“数据结构及其所有相关的方法”。 有很多方法可以用来说明这两个术语之间的区别&…

python执行shell

0x00:前言 正常一个网站分为服务端和客户端&#xff0c;因为是正向的&#xff0c;所以服务端是在目标机器上的&#xff0c;客户端则是攻击者机器上&#xff0c;在这里要感谢MiaGz大师傅&#xff0c;这里很多都是参考了MiaGz大师傅的文章写出来的&#xff0c;进行了一点个人修改…

STM32/GD32_分散加载

Q&#xff1a;如何将一个变量、某个源文件的函数在编译阶段就存储在用户指定的区域&#xff1f; KEIL环境&#xff1a;.map后缀文件、.sct后缀文件 IAR环境&#xff1a;.map后缀文件、.icf后缀文件 【map文件】 对固件里面的变量、函数、常量等元素的存储空间进行分配的说明…

【android开发-04】android中activity的生命周期介绍

1&#xff0c;返回栈 android中使用任务task来管理activity&#xff0c;一个任务就是一组存放在栈里的活动的集合&#xff0c;这个栈被称为返回栈。栈是一种先进先出的数据结构。当我们启动一个新的活动&#xff0c;他会在返回栈中人栈&#xff0c;并处以栈顶的位置&#xff0…

刘恋对话贾樟柯:焦虑往往是因为我们还有的选

11月29日&#xff0c;由房产服务国民品牌我爱我家与贾樟柯联合呈现的《住进每一种生活》&#xff0c;在乐迷和网友的热烈期盼下迎来了第三期。自首期节目在腾讯视频和极光TV播出以来&#xff0c;《住进每一种生活》频频在社交媒体上引发观众热议。 《住进每一种生活》以六位名…

指纹芯片的工作原理及应用领域详解

指纹芯片是一种利用指纹识别技术的电子设备,可以通过扫描人体指纹的纹理特征,将其转化为数字化信息并进行存储和识别。指纹芯片广泛应用于各个领域,包括智能手机、银行和金融、门禁系统、身份验证等,因其高度准确、快速便捷的特点,得到了广大用户的青睐。 指纹芯片的原理是基于…

从订阅式需求发展,透视凌雄科技DaaS模式增长潜力

订阅制&#xff0c;C端消费者早已耳熟能详&#xff0c;如今也凭借灵活、服务更新稳定的特点&#xff0c;逐渐成为B端企业服务的新热点。 比如对中小企业而言&#xff0c;办公IT设备等配套支出都必不可少&#xff0c;但收入本身并不稳定&#xff0c;购置大堆固定资产&#xff0…