springboot实战(十)之全网最全RabbitMQ集成

news2025/1/24 17:35:02

序言

首先我要抛出几个问题让大家思考一下:为什么你的项目中要用MQ呢?使用MQ为你解决了什么问题?当然解决问题的同时它又有哪些弊端值得注意?

如果你不太清楚或者你根本没有考虑过,那么请往下看你会找到你想要的答案。

1.介绍

官网介绍:RabbitMQ is the most widely deployed open source message broker.(RabbitMQ是部署最广泛的开源信息代理。)
RabbitMQ采用Erlang语言开发,是AMQP(Advanced Message Queuing Protocol)的标准实现。支持持久化,支持多种客户端,如 Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP 等。常用于分布式系统中的存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

2.特点

  • 分布式部署,支持集群模式、跨区域部署,以满足高可用、高吞吐量应用场景;
  • 异步消息传递,支持多种消息传递协议、消息队列、传递确认机制,灵活的路由消息到队列,多种交换类型;
  • 良好的开发者体验,可在许多操作系统及云环境中运行,并为大多数流行语言提供各种开发工具;
  • 可插拔身份认证授权,支持 TLS(Transport Layer Security)和 LDAP(Lightweight Directory Access Protocol),轻量且容易部署到内部、私有云或公有云中;
  • 有专门用于管理和监督的HTTP-API、命令行工具和 UI;
  • 支持连续集成,可以插件方式灵活地扩展 RabbitMQ 的功能。

优点:

  • 由于 Erlang 语言的特性,RabbitMQ 性能较好、高并发;
  • 有消息确认机制和持久化机制,可靠性高;
  • 高度灵活可定制的路由;
  • 管理界面较丰富,在互联网公司也有较大规模的应用;
  • 健壮、稳定、易用、跨平台、支持多种语言客户端、文档齐全;
  • 社区活跃度高,更新快。

缺点:

  1. 尽管结合 Erlang 语言本身的并发优势,性能较好,但是不利于做二次开发和维护;
  2. 实现了代理架构,意味着消息在发送到客户端之前可以在中央节点上排队。此特性使得 RabbitMQ 易于使用和部署,但使得其运行速度较慢,因为中央节点增加了延迟,消息封装后也比较大;
  3. 需要学习比较复杂的接口和协议,学习和维护成本较高。

3.安装

安装官网:RabbitMQ

RabbitMQ支持window、unix、macos等平台安装,按自己的需要进行安装

 

管理端页面:http://localhost:15672/ 

账号密码:guest 

4.集成

因为springboot已经有mq相关starter,所以我们之间引用依赖

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

yml文件配置信息:

spring:
  #rabbitmq配置
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    virtual-host: /

配置文件:

package com.iterge.iterge_pre.config;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author liuph
 * @date 2023/10/17 15:50:37
 */
@Configuration
public class RabbitmqConfig {
    public static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    public static final String QUEUE_INFORM_SMS = "queue_inform_sms";
    public static final String EXCHANGE_TOPICS_INFORM="exchange_topics_inform";
    public static final String ROUTINGKEY_EMAIL="inform.#.email.#";
    public static final String ROUTINGKEY_SMS="inform.#.sms.#";

    //声明交换机
    @Bean(EXCHANGE_TOPICS_INFORM)
    public Exchange EXCHANGE_TOPICS_INFORM(){
        //durable(true) 持久化,mq重启之后交换机还在
        return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_INFORM).durable(true).build();
    }

    //声明QUEUE_INFORM_EMAIL队列
    @Bean(QUEUE_INFORM_EMAIL)
    public Queue QUEUE_INFORM_EMAIL(){
        return new Queue(QUEUE_INFORM_EMAIL);
    }
    //声明QUEUE_INFORM_SMS队列
    @Bean(QUEUE_INFORM_SMS)
    public Queue QUEUE_INFORM_SMS(){
        return new Queue(QUEUE_INFORM_SMS);
    }

    //ROUTINGKEY_EMAIL队列绑定交换机,指定routingKey
    @Bean
    public Binding BINDING_QUEUE_INFORM_EMAIL(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
                                              @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_EMAIL).noargs();
    }
    //ROUTINGKEY_SMS队列绑定交换机,指定routingKey
    @Bean
    public Binding BINDING_ROUTINGKEY_SMS(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
                                          @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_SMS).noargs();
    }
}

生产者配置:

package com.iterge.iterge_pre.mq;

import com.iterge.iterge_pre.config.RabbitmqConfig;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author liuph
 * @date 2023/10/17 15:52:48
 */
@Component
public class ProducerService {
    @Autowired
    private RabbitMessagingTemplate mqTemplate;

    public void sendMag(String msg){
        mqTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_TOPICS_INFORM, "inform.email", msg);
    }
}

消费者配置:

package com.iterge.iterge_pre.mq;

import com.iterge.iterge_pre.config.RabbitmqConfig;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @author liuph
 * @date 2023/10/17 15:53:04
 */
@Component
public class ConsumerService {
    //监听email队列
    @RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_EMAIL})
    public void receive_email(Message message, Channel channel){
        String body = new String(message.getBody());
        System.out.println("消费者:QUEUE_INFORM_EMAIL msg_"+body);
    }
    //监听sms队列
    @RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_SMS})
    public void receive_sms(Message message, Channel channel){
        String body = new String(message.getBody());
        System.out.println("消费者:QUEUE_INFORM_SMS msg_"+body);
    }

}

创建Controller

package com.iterge.iterge_pre.controller;

import com.iterge.iterge_pre.entity.Response;
import com.iterge.iterge_pre.mq.ProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author liuph
 * @date 2023/10/17 15:58:32
 */
@RestController
@RequestMapping("mq")
public class MQController {
    @Autowired
    private ProducerService producerService;

    @GetMapping("send/{msg}")
    public Response<String> send(@PathVariable(value = "msg") String mag){
        producerService.sendMag(mag);
        return Response.ok();
    }
}

测试:

控制台信息:

 如上,消费者成功消费到hi_rabbitmq

5.思考

所以文章读完了,开篇的问题思考的有结果了吗?

没有结果也没关系,下面我们做下总结:

1. 为什么你的项目中要用MQ呢?

这个问题要结合自己的业务场景来判断,比如多服务调用时需要应用解偶,高并发场景下提高需要保证服务的高可用,高性能等。

2.使用MQ为你解决了什么问题?

那MQ为我们解决什么问题呢,一般可以用6个字来概括:解偶、异步、削峰

解偶场景:比如当B、C系统需要用到A系统的数据时,A系统要分别调用B、C两端的接口就行数据传输,如果这是在来个D系统也需要A的数据,那么A系统还要改造代码,这时我们就可以把方案调整为通过MQ就行数据传输,A生产数据,别的系统需要数据之间消费就行了

异步场景:比如A系统需要调用B系统的接口进行业务操作,而B接口的业务逻辑又要用到C系统的接口,假如a自身业务处理耗时1s,a调b耗时2s,b调c耗时2秒,那整个流程耗时5s;

如果把方案调整为,a把数据放到MQ中,b系统消费后进行业务处理,假如a自身业务处理耗时1s,MQ耗时1s,共耗时2s,大大提高了业务处理能力

削峰场景:假如现在有1000w个用户请求a系统,所有请求的数据要存到数据库中,如果这些请求数据一股脑儿的都往数据库怼,那可能导致的结果是数据库顶不住,连接出现异常或者宕机,这种情况下改用MQ的方式,当数据进来时先把数据存的mq,b系统再慢慢的按照数据库能处理的并发量,从消息队列中慢慢拉取消息。在生产中,这个短暂的高峰期积压是允许的。

3.当然解决问题的同时它又有哪些弊端值得注意?

而在解决上面的问题的同时,MQ也有一些弊端需要我们注意,由于链路变长,就有存在一些数据一致性的问题,比如数据丢失、重复消费、顺序消费等问题就出现。

本文章针对这些弊端问题暂时先不做讲述。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安科瑞预付费电能管理系统在学生公寓的应用与分析

安科瑞 崔丽洁 摘要&#xff1a;论文设计了适用于学生公寓的自助式预付费控电控水管理系统&#xff0c;采用多种智能功能&#xff0c;可以监测和显示漏电现象&#xff0c;通过短路、跳线、零线接地等方式防范和记录用户的偷电行为&#xff0c;通过报警和拉闸防止事故的发生。预…

天洑参展第三十五届中国仿真大会

2023年10月14日&#xff0c;由安徽省政府、中国仿真学会主办的第三十五届中国仿真大会在安徽合肥召开。中国仿真大会自1989年起每年举办一次&#xff0c;是国内仿真领域规模最大、综合性和影响力最强的大型综合性学术会议。本届学术会以“数字经济、仿真发展”为主题&#xff0…

家电商城小程序制作的流程和好处

在当今的数字化时代&#xff0c;拥有一个自己的家电商城小程序对于家电销售商来说是必不可少的。它不仅可以帮助你扩大市场覆盖范围&#xff0c;还可以提高销售额和客户满意度。那么&#xff0c;如何制作一个家电商城小程序呢&#xff1f;以下是详细的流程和好处。 首先&#x…

【动态规划】1143. 最长公共子序列、1035. 不相交的线、53. 最大子数组和

提示&#xff1a;努力生活&#xff0c;开心、快乐的一天 文章目录 1143. 最长公共子序列&#x1f4a1;解题思路&#x1f914;遇到的问题&#x1f4bb;代码实现&#x1f3af;题目总结 1035. 不相交的线&#x1f4a1;解题思路&#x1f914;遇到的问题&#x1f4bb;代码实现&#…

HBase:大数据中的NoSQL

HBase概述 Hbase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统&#xff0c;用于存储海量的结构化或者半结构化&#xff0c;非结构化的数据&#xff0c;底层上的数据是以二进制流的形式存储在 HDFS 上的数据块中的 HBase应用场景 写密集型应用&#xff0c;每天写入…

E055-web安全应用-File Inclusion文件包含漏洞初级

课程名称&#xff1a; E055-web安全应用-File Inclusion文件包含漏洞初级 课程分类&#xff1a; web安全应用 实验等级: 中级 任务场景: 【任务场景】 小王接到磐石公司的邀请&#xff0c;对该公司旗下网站进行安全检测&#xff0c;经过一番检查发现了该论坛的某个页面存…

强烈推荐!超低温冰箱监控教程

超低温冰箱监控是在医疗、科研和工业领域中至关重要的技术&#xff0c;被用于储存和保护生物样本、药物、疫苗以及其他温度敏感的物品。有效的监控系统可以确保这些贵重物品在极端低温条件下的安全性和稳定性。 客户案例 医疗研究院 广东某医疗研究院需要存储大量的生物样本和…

【Cisco ios的三种命令模式,可收藏!】

一&#xff1a;前言 IOS(InternetWork Operating System 互联网操作系统)是Cisco网络设备的核心系统软件&#xff0c;IOS用户界面是命令行接口界面&#xff0c;用户可以通过输入命令实现对网络设备的配置和管理。 为了安全&#xff0c;IOS提供了三种命令行模式&#xff0c;分…

嵌入式实时操作系统的设计与开发(调度策略学习)

将调度分为两层&#xff0c;上层为策略&#xff0c;下层为机制&#xff0c;并且采用策略与机制分离的设计原则&#xff0c;可以方便灵活地扩展调度策略&#xff0c;而不改变底层的调度机制。 调度策略就是如何确定线程的CPU、优先级prio等参数&#xff0c;线程是按照FIFO&…

Sui第六轮资助:15个项目共获得106万美元的资助

近日&#xff0c;Sui基金会宣布了15个项目获得共计106万美元的资助&#xff0c;用于构建项目以推动Sui的采用和发展。要获得资助&#xff0c;项目必须提交详细描述其正在构建的内容、逐项预算、关键里程碑、团队经验以及对Sui社区预期贡献的提案。 获得资助的15个项目致力于跨…

WPF 用户控件依赖注入赋值

前言 我一直想组件化得去开发WPF&#xff0c;因为我觉得将复杂问题简单化是最好的 如何组件化开发 主窗口引用 <Window x:Class"WpfApp1.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.…

如何将前后端分离项目部署到本地的Docker Desktop容器运行并且访问

文章目录 前言 完成了客户的一个前后端分离项目&#xff0c;要求部署到客户电脑上去展示&#xff0c;那肯定不能直接把代码弄上去跑呀~~~&#xff0c;于是我就想把他们都打包部署到本地的docker容器里面&#xff0c;方便运行和访问&#xff0c;so&#xff0c;以下内容就详细介…

封装canvas选择区域的组件

大家好&#xff0c;我是南宫&#xff0c;最近我刚完成了一个canvas相关组件的封装。我个人其实很怕canvas和地图&#xff0c;就感觉这里有很复杂的操作&#xff0c;搞不懂&#xff0c;所以这次封装完了以后&#xff0c;决定写一篇博客来记录。 首先我先简单介绍一下这个组件的…

【仙逆】王林极限跑酷,藤厉自食恶果,仙逆战斗获好评,张虎命运被改写

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 最新一集《仙逆》已经更新&#xff0c;相信很多小伙伴都已经先睹为快&#xff0c;在击杀了白展之后&#xff0c;张虎和王林担心其师傅即墨老人报复&#xff0c;因此躲到看似安全的藤家城&#xff0c;以为那里有…

MySQL学习(三)——多表连接查询

文章目录 1. 多表关系1.1 一对多1.2 多对多1.3 一对一 2. 概述2.1 数据准备2.2 简单查询2.3 分类 3. 内连接4. 外连接5. 自连接5.1 自连接查询5.2 联合查询 6. 子查询6.1 概念6.2 标量子查询6.3 列子查询6.4 行子查询6.5 表子查询 1. 多表关系 项目开发中&#xff0c;在进行数…

UE5 运行时生成距离场数据

1.背景 最近有在运行时加载模型的需求&#xff0c;使用DatasmithRuntimeActor可以实现&#xff0c;但是跟在编辑器里加载的模型对比起来&#xff0c;室内没有Lumen的光照效果。 图1 编辑器下加载模型的效果 图2 运行时下加载模型的效果 然后查看了距离场的数据&#xff0c;发现…

leetcode-48.旋转图像

1. 题目 leetcode题目链接 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 2. 编程 矩阵转置&#xff1a; 遍历矩阵&#x…

EKP接口开发Webservice服务和Restservice服务以及定时任务Demo

继承com.landray.kmss.sys.webservice2.interfaces.ISysWebservice&#xff0c;同时在接口上使用WebService注解将其标识为WebService接口 package com.landray.kmss.third.notify.webservice;import com.alibaba.fastjson.JSONObject; import com.landray.kmss.sys.webservic…

CAD图形导出为XAML实践

文章目录 一、前言二、方法与实践2.1 画出原图&#xff0c;借第三方工具导出至指定格式2.2 CAD导出并转换2.3 两种方法的优劣2.3.1 直接导出代码量大2.3.2 导入导出需要调参 三、总结 一、前言 上位机通常有一个设备/场景界面&#xff0c;该界面用于清晰直观地呈现设备状态。 …

线程通信java

有包子 不做了 唤醒别人等地自己 this.notifyAll(); this.wait() package TheadCpd;public class TheadCpd {//目标&#xff1a;了解线程通信public static void main(String[] args) {//需求&#xff1a;3个人生产或者线程 负责生产包子 每个线程生产1个包子放桌子上// 2…