[MQ] SpringBoot使用直连交换机Direct Exchange

news2024/11/23 14:59:22

✨个人主页:沫洺的主页

📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                           📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

                           📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏     

💖💖如果文章对你有所帮助请留下三连✨✨

1️⃣环境搭建

创建SpringBoot项目,引入相关依赖

 application.properties配置rabbitmq配置信息

spring.rabbitmq.host=192.168.0.109
spring.rabbitmq.port=5670
#如果使用的是/,可以不用配置,因为默认就是/
spring.rabbitmq.virtual-host=/
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

2️⃣消费者接收消息

@RabbitHandler注解: 当spring扫到该注解,就当成消费者

@RabbitListener注解: 绑定队列Queue与交换机Exchange
durable持久化
autoDelete自动删除
type=ExchangeTypes.DIRECT交换机类型为直连交换机,不写默认直连
key: 就是Routing key

@Component
public class DirectConsumer {

    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-01", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    public void process2(Message message){
        String msg = new String(message.getBody());
        System.out.println("消费者1-1收到:"+msg+"");
        //这里写业务逻辑代码
    }
}

3️⃣生产者发送消息

注入RabbitTemplate,调用convertAndSend方法发送消息

参数一:交换机 参数二: Routing key 参数三: 消息

@Component
public class DirectProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(){

        rabbitTemplate.convertAndSend("211-DirectExchage-01","211-Direct-RoutingKey-01","生产者发送的第一条消息");
        //System.out.println("生产者第一条消息发送成功");
    }
}

启动类调用sendMessage发送

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
        //调用生产者发送消息
        DirectProducer producer = context.getBean(DirectProducer.class);
        producer.sendMessage();
    }
}

💦多个消费者消费同一个队列

当生产者发送多条消息时,同一个队列的多个消费者去接收消息

生产者发送多条消息

@Component
public class DirectProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(){
        rabbitTemplate.convertAndSend("211-DirectExchage-01","211-Direct-RoutingKey-01","生产者发送的第一条消息");
        System.out.println("生产者第一条消息发送成功");
        rabbitTemplate.convertAndSend("211-DirectExchage-01","211-Direct-RoutingKey-01","生产者发送的第二条消息");
        System.out.println("生产者第二条消息发送成功");
    }
}

同一个队列的多个消费者去接收消息

都是value = "211-DirectQueue-01"的队列

@Component
public class DirectConsumer {

    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-01", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    public void process2(Message message){
        String msg = new String(message.getBody());
        System.out.println("消费者1-1收到:"+msg+"");
        //这里写业务逻辑代码
    }
    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-01", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    public void process2(Message message){
        String msg = new String(message.getBody());
        System.out.println("消费者1-2收到:"+msg+"");
        //这里写业务逻辑代码
    }
}

可以理解为快递员送快递,只关注哪一家(队列)签收的快递,而不关注该家哪个成员(消费者)签收的快递,(只是在签收时的消费者是轮循的)

像这种同一队列多个消费者的好处就是保障了高可用性,只要有一个消费者就能保障接收到消息

💦多个消费者消费不同的队列

当生产者发送多条消息时,不同队列的多个消费者去接收消息

生产者发送多条消息

@Component
public class DirectProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(){
        rabbitTemplate.convertAndSend("211-DirectExchage-01","211-Direct-RoutingKey-01","生产者发送的第一条消息");
        System.out.println("生产者第一条消息发送成功");
        rabbitTemplate.convertAndSend("211-DirectExchage-01","211-Direct-RoutingKey-01","生产者发送的第二条消息");
        System.out.println("生产者第二条消息发送成功");
    }
}

不同队列的多个消费者去接收消息

不同队列value = "211-DirectQueue-01"和value = "211-DirectQueue-02"

@Component
public class DirectConsumer {

    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-01", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    public void process2(Message message){
        String msg = new String(message.getBody());
        System.out.println("消费者1收到:"+msg+"");
        //这里写业务逻辑代码
    }
    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-02", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    public void process2(Message message){
        String msg = new String(message.getBody());
        System.out.println("消费者2收到:"+msg+"");
        //这里写业务逻辑代码
    }
}

同样的不是同一家(队列)的成员(消费者),在签收快递时,要签收自己家所有快递(消息)

⛅消费者重试机制/自动应答

application.properties配置

  1. 配置消费者应答模式
  2. 配置rabbitmq重试配置信息
#开启消费者应答模式为 auto自动应答 manual手动应答
spring.rabbitmq.listener.direct.acknowledge-mode = auto
#spring.rabbitmq.listener.simple.acknowledge-mode = auto

#开启消费者自动重试机制,也就是消费者函数只要抛出异常,就会触发重试 false关闭
spring.rabbitmq.listener.simple.retry.enabled=true
#设置重试最大次数
spring.rabbitmq.listener.simple.retry.max-attempts=5
#设置重试时间最大间隔
spring.rabbitmq.listener.simple.retry.max-interval= 8000ms
#设置重试时间间隔
spring.rabbitmq.listener.simple.retry.initial-interval=1000ms
#设置重试时间间隔的倍数
spring.rabbitmq.listener.simple.retry.multiplier=2

当不配置重试机制时,消费者应答出现异常不处理时,就会出现死循环

如下代码段

@Component
public class DirectConsumer {

    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-01", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    public void process2(Message message){
        String msg = new String(message.getBody());
        System.out.println("消费者1-1收到:"+msg+"");
        //这里写业务逻辑代码
        int i = 1/0//会出现死循环
    }
}

配置后

⛅手动应答模式

配置手动应答,取消重试机制

#开启消费者应答模式为 auto自动应答 manual手动应答
spring.rabbitmq.listener.direct.acknowledge-mode = manual
#开启消费者自动重试机制,也就是消费者函数只要抛出异常,就会触发重试
spring.rabbitmq.listener.simple.retry.enabled=false

手动应答模式

@Component
public class DirectConsumer {

    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-01", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    //手动应答
    public void process1(Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        System.out.println("消费者1-1收到:"+msg+ DateUtil.format(DateUtil.date(),"HH:ss"));
        //获取应答标签
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            int i = 1/0;//会出现死循环
            //手动应答 参数一:消息标识 参数二:true批量应答,false单个应答
            channel.basicAck(deliveryTag,false);
        } catch (Exception ex) {
            //把异常消息插入数据库
            System.out.println("消费者1-1收到:"+msg+"出现异常信息插入数据库");
            System.out.println("异常信息: "+ex.getMessage());
            channel.basicAck(deliveryTag,false);
        }
    }
}

 出现异常,将异常消息插入数据库后,这样保障应答后在队列中不堵,然后再让生产者发送消息

channel.basicAck正常应答

channel.basicCancel取消应答

channel.basicReject拒绝应答

没有重试机制,需要自己去写,所以一般不会使用手动应答

🧭投递业务对象

一般生产的都是领域对象dto

例如

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserRegisterOk {

    private String name;
    private String phone;
}

生产者生产对象

@Component
public class DirectProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(){
        UserRegisterOk userRegisterOk = UserRegisterOk.builder().name("张三").phone("123456").build();
        //要将对象序列化,转成字符串,使用消息转换器MessageConverter
        rabbitTemplate.convertAndSend("211-DirectExchage-01","211-Direct-RoutingKey-01",userRegisterOk);
        System.out.println("生产者生产对象发送成功");
    }
}

消费者接收对象

@Component
public class DirectConsumer {

    @RabbitHandler
    @RabbitListener(bindings =
    @QueueBinding(value  = @Queue(value = "211-DirectQueue-01", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "211-DirectExchage-01", type = ExchangeTypes.DIRECT),
            key = "211-Direct-RoutingKey-01"))
    public void process4(UserRegisterOk userRegisterOk){
        System.out.println("消费者收到:"+userRegisterOk.getName()+","+userRegisterOk.getPhone());
    }
}

运行后报错

 配置序列化

@Configuration
public class RabbitConfig {

    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
}

💖补充写法

@Component
public class DirectConsumer {
    private static  final  String ENAME = "211-DirectExchage-01";
    private static  final  String QNAME = "211-DirectQueue-01";
    private static  final  String KEY = "211-Direct-RoutingKey-01";
    //定义一个交换机
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(ENAME, true, false);
    }
    //定义一个队列
    @Bean
    public Queue directQueue(){
        return QueueBuilder.durable(QNAME).build();
    }
    //创建队列和交换机的绑定关系
    @Bean
    public Binding binding(){
        return BindingBuilder.bind(directQueue()).to(directExchange()).with(KEY);
    }

    @RabbitHandler
    @RabbitListener(queues =QNAME)
    public void process4(UserRegisterOk userRegisterOk){
        System.out.println("消费者收到:"+userRegisterOk.getName()+","+userRegisterOk.getPhone());
    }
}

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

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

相关文章

Bootstrap-栅格实例(二)

栅格实例 进入官网 选择3.0的中文文档: 选择组件: 选择缩放图: 选择这个,复制代码: 把代码拷贝到,新创建的模板固定container里面: 删除靠过来的多余的row: 修改div的calss&…

【信息奥赛实训】Week1——STL 与基础数据结构专题训练

【信息奥赛实训】Week1-Lab-STL 作者|Rickyの水果摊 时间|2022年11月20日 实训概要 实训专题 STL 与基础数据结构专题训练 实训目的 掌握STL常用的算法、容器、容器适配器的使用方法。能够利用STL的算法、容器、容器适配器求解问题。 题目列表 A&…

HTML小游戏9 —— 潜行游戏《侠盗罗宾汉》(附完整源码)

💂 网站推荐:【神级源码资源网】【摸鱼小游戏】🤟 风趣幽默的前端学习课程:👉28个案例趣学前端💅 想寻找共同学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】💬 免费且实用的计算机相关知…

紫外线杀菌器

一、概述 紫外线杀菌器是利用波长为225-275nm的紫外线对微生物的杀灭而使水中菌类得以净化。当水流经消毒仪时,高强度杀菌作用的紫外线即将水中细菌杀灭。本产品彻底解决了饮用水二次污染细菌超标问题,同时也适用于饮料、食品、游泳池等用水的消毒处理。…

Linux基本指令——综合操作

bc指令bc指令其实就是Linux下的计算器Ctrl c退出也可以通过管道进行输出。bc命令并不常用,主要是见见。uname -r指令语法:uname [选项]作用:uname可以用来获取电脑或者操作系统的相关信息。选项:-a或–all 详细输出所有信息&…

ConsulManager安装

地址 地址: https://github.com/starsliao/ConsulManager使用yum部署consul 在这里可以直接使用yum安装部署consul这个组件 # 使用yum部署consul yum install -y yum-utils yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.re…

(续)SSM整合之springmvc笔记(RESTful之RESTful案例)(P148-153)

目录 RESTful案例 一 . 准备工作 1 . 准备实体类 2 .准备dao模拟数据 3. 创建控制层EmployeeController 二 功能清单 三 . 具体功能:查询所有员工数据 ①控制器方法 ②创建employee_list.html RESTful案例 一 . 准备工作 和传统CRUD 一样,…

【前沿技术RPA】 一文了解UiPath 通过Invoke Method 和 Invoke Code增强自动化功能

🐋作者简介:博主是一位.Net开发者,同时也是RPA和低代码平台的践行者。 🐬个人主页:会敲键盘的肘子 🐰系列专栏:UiPath 🦀专栏简介:UiPath在传统的RPA(Robotic…

[附源码]Python计算机毕业设计_旅游系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

多表操作(外键)

多表操作 外键 外键(foreign key): 外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系。 主表(父表):对于两个具有关联关系的表而言,相关联字段中…

HTML+CSS+JS网页设计期末课程大作业____(航天月球响应式 3页)

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材,DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 公司官网网站 | 企业官网 | 酒店官网 | 等网站的设计与制 | HTML期末大学生网页设计作业,Web大学生网页 HTML:结构 CSS&#…

【Java八股文总结】之Spring

文章目录Spring一、Spring介绍1、Spring是什么?特性?2、Spring有哪些模块?3、Spring中的设计模式?二、IOC1、基本概念2、什么是IOC?什么是DI?Q:为什么要使用 IOC 呢?3、Spring IOC的…

一文快速学会hadoop完全分布式集群搭建,很详细

文章目录前言一、准备工作二、克隆三台虚拟机并进行网络配置克隆虚拟机克隆引导修改网络配置验证验证方式一验证方式二三、安装jdk和hadoop四、ssh免密登录配置概述生成公钥和私钥把公钥拷贝到三台虚拟机上面去验证把hadoop103 和 hadoop104的免密登录配置安装上面的操作再做一…

ZYNQ - 无DDR固化程序(代码运行在OCM上)

写在前面 ZYNQ固化时,正常情况下都需要DDR参与,但是有时硬件设计时,可能将DDR去掉或设计出错,这将导致ZYNQ无法正常固化,之前有写过一个使用静态链接库进行无DDR固化的文章,当时那个是压缩了FSBL的相关代码…

yolov5剪枝实战3: yolov5-slimming项目运行演示

1. 下载项目文件 从百度网盘下载并解压 网盘地址,文末有链接:包括项目完整源代码、数据集、原理的课件说明等。 解压源码: yolov5-6.1-slimming.zip项目没有从yolov5 github上直接克隆项目文件,而是从百度网盘上下载项目文件并解压,因为yolov5原始的代码是没有带网络剪枝的,…

ElasticSearch - ​开启搜索的新境界

You Know, for Search ElasticSearch官网 开启搜索的新境界 Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上。 Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库。但是 Lucene 仅仅只是一个库。为了充分…

STM32+ MAX30102通过指尖测量心率+血氧饱和度

一、前言 重要的事情放在最前面:max30102只适用于指尖手指测量,不适用与手腕手指测量,如需做成可穿戴样式选择传感器的小伙伴请pass掉他,因为他只有红光和红外2种光,不够充足的数据源去运算。 由于一些原因&#xff0c…

个人开发者轻松接入支付回调

易支付(https://epay.jylt.cc)- 个人支付如此简单 随着技术的发展,现在个人构建一个网站的成本越来越低,越来越多的个人开发者拥有了自己的网站。个人搭建网站除了带来成就感之外如果能赚一些额外的收入岂不更好? 事…

多目标优化问题的研究概述(Matlab代码实现)

🍒🍒🍒欢迎关注🌈🌈🌈 📝个人主页:我爱Matlab 👍点赞➕评论➕收藏 养成习惯(一键三连)🌻🌻🌻 🍌希…

ECMAScript

介绍 JavaScript和ECMAScript的区别 html和css的解析在两款浏览器是不同的效果,比如一个页面能在IE解析,但是不能在网景浏览器解析 后面出现了脚本语言,JavaScript,提供了丰富功能,比如输入密码进行正则的判断提示 …