当前位置: 首页 > news >正文

RabbitMQ基础(2)——发布订阅/fanout模式 topic模式 rabbitmq回调确认 延迟队列(死信)设计

目录

  • 引出
  • 点对点(simple)
  • Work queues 一对多
  • 发布订阅/fanout模式
    • 以登陆验证码为例
    • pom文件导包
    • application.yml文件
    • rabbitmq的配置
    • 生产者生成验证码,发送给交换机
    • 消费者消费验证码
  • topic模式
    • 配置类增加配置
    • 生产者发送信息
    • 进行发送
    • 控制台查看
  • rabbitmq回调确认
    • 配置类
    • 验证生产者发送是否成功
  • 延迟队列(死信)设计
    • java代码步骤
      • 创建正常+死信队列
      • 配置类+常量
      • 生产者到正常队列
      • 消费者进行延迟消费
    • 延迟队列插件安装
      • 访问官网
      • 进入rabbitmq docker容器
      • 上传到linux服务器
      • 拷贝插件到容器中
      • 进入容器安装插件
      • 打开管理页面
  • 总结

引出


1.rabbitmq队列方式的梳理,点对点,一对多;
2.发布订阅模式,交换机到消费者,以邮箱和手机验证码为例;
3.topic模式,根据规则决定发送给哪个队列;
4.rabbitmq回调确认,setConfirmCallback和setReturnsCallback;
5.死信队列,延迟队列,创建方法,正常—死信,设置延迟时间;

点对点(simple)

点对对方式传输

在这里插入图片描述

Work queues 一对多

1个生产者多个消费者

在这里插入图片描述

在这里插入图片描述

发布订阅/fanout模式

生产者通过fanout扇出交换机群发消息给消费者,同一条消息每一个消费者都可以收到。

在这里插入图片描述

以登陆验证码为例

pom文件导包

<!--        qq邮箱--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><!--        阿里云短信验证码相关包--><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.5.3</version></dependency><!--        queue的包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>

application.yml文件

server:port: 9099spring:# 模块的名字application:name: user-auth# 邮箱的配置mail:host: smtp.qq.comport: 587username: xxxxpassword: xxxxx# rabbitmq的配置rabbitmq:host: 192.168.111.130port: 5672username: adminpassword: 123logging:level:com.tianju.auth: debug

rabbitmq的配置

需要用到的常量

package com.tianju.auth.util;/*** rabbitmq的常量*/
public interface RabbitMqConstants {String MQ_MAIL_QUEUE="mq_email_queue";String MQ_PHONE_QUEUE="mq_phone_queue";String MQ_FANOUT_EXCHANGE="mq_fanout_exchange";// 参数 String name, boolean durable, boolean exclusive, boolean autoDeleteboolean durable = true;boolean exclusive = false;boolean autoDelete = false;}

RabbitMqConfig.java配置

邮箱队列,电话队列,交换机;

邮箱绑定交换机,电话绑定交换机;

创建队列参数说明:

参数说明
name字符串值,queue的名称。
durable布尔值,表示该 queue 是否持久化。 持久化意味着当 RabbitMQ 重启后,该 queue 是否会恢复/仍存在。 另外,需要注意的是,queue 的持久化不等于其中的消息也会被持久化。
exclusive布尔值,表示该 queue 是否排它式使用。排它式使用意味着仅声明他的连接可见/可用,其它连接不可见/不可用。
autoDelete布尔值,表示当该 queue 没“人”(connection)用时,是否会被自动删除。

不指定 durable、exclusive 和 autoDelete 时,默认为 truefalsefalse 。表示持久化、非排它、不用自动删除。

创建交换机参数说明

参数说明
name字符串值,exchange 的名称。
durable布尔值,表示该 exchage 是否持久化。 持久化意味着当 RabbitMQ 重启后,该 exchange 是否会恢复/仍存在。
autoDelete布尔值,表示当该 exchange 没“人”(queue)用时,是否会被自动删除。

不指定 durable 和 autoDelete 时,默认为 truefalse 。表示持久化、不用自动删除

package com.tianju.auth.config;import com.tianju.auth.util.RabbitMqConstants;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMqConfig {@Bean // 邮箱的队列public Queue mailQueue(){return new Queue(RabbitMqConstants.MQ_MAIL_QUEUE,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete);}@Bean // 电话的队列public Queue phoneQueue(){return new Queue(RabbitMqConstants.MQ_PHONE_QUEUE,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete);}@Bean // 交换机public FanoutExchange fanoutExchange(){return new FanoutExchange(RabbitMqConstants.MQ_FANOUT_EXCHANGE,RabbitMqConstants.durable,RabbitMqConstants.autoDelete);}@Beanpublic Binding mailBinding(){return BindingBuilder.bind(mailQueue()).to(fanoutExchange());}@Beanpublic Binding phoneBinding(){return BindingBuilder.bind(phoneQueue()).to(fanoutExchange());}}

生产者生成验证码,发送给交换机

接口

package com.tianju.auth.service;public interface IUserService {/*** 生产者生成信息发送给交换机* @param msg 信息,这里是验证码*/void sendCode(String msg);
}

实现

package com.tianju.auth.service.impl;import com.tianju.auth.service.IUserService;
import com.tianju.auth.util.RabbitMqConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
@Slf4j
public class UserServiceImpl implements IUserService {@Autowiredprivate RabbitTemplate rabbitTemplate;@Overridepublic void sendCode(String msg) {rabbitTemplate.convertAndSend(RabbitMqConstants.MQ_FANOUT_EXCHANGE,"routingkey.fanout",msg);log.debug("[生产者向交换机:] 发送一条信息:{}",msg);}}

测试类生成验证码,发给交换机

在这里插入图片描述

package com.tianju.auth.service.impl;import cn.hutool.core.lang.Snowflake;
import com.tianju.auth.service.IUserService;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)public class UserServiceImplTest {@Autowiredprivate IUserService userService;@Testpublic void sendCode() {String code = new Snowflake().nextIdStr().substring(0, 6);System.out.println(code);userService.sendCode(code);}
}

消费者消费验证码

package com.tianju.auth.consumer;import com.tianju.auth.service.IEmailService;
import com.tianju.auth.util.RabbitMqConstants;
import com.tianju.auth.util.SMSUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class UserConsumer {@Autowiredprivate IEmailService emailService;@RabbitListener(queues = RabbitMqConstants.MQ_MAIL_QUEUE)public void emailConsumer(String msg){log.debug("[email消费者:]消费{}",msg);emailService.sendEmail("xxxx@qq.com", "登陆验证码", msg);}@RabbitListener(queues = RabbitMqConstants.MQ_PHONE_QUEUE)public void phoneConsumer(String msg){log.debug("[phone消费者:]消费{}",msg);SMSUtil.send("xxxx", msg);}}

在这里插入图片描述

topic模式

在这里插入图片描述

例如: routingkey: my.orange.rabbit —-> Q1,Q2

在这里插入图片描述

配置类增加配置

package com.tianju.auth.util;/*** rabbitmq的常量*/
public interface RabbitMqConstants {String MQ_MAIL_QUEUE="mq_email_queue";String MQ_PHONE_QUEUE="mq_phone_queue";String MQ_FANOUT_EXCHANGE="mq_fanout_exchange";String MQ_TOPIC_EXCHANGE="mq_topic_exchange";String MQ_TOPIC_QUEUE_A = "mq_topic_queue_a";String MQ_TOPIC_QUEUE_B = "mq_topic_queue_b";// 参数 String name, boolean durable, boolean exclusive, boolean autoDeleteboolean durable = true;boolean exclusive = false;boolean autoDelete = false;}
package com.tianju.auth.config;import com.tianju.auth.util.RabbitMqConstants;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMqConfig {@Bean // 邮箱的队列public Queue mailQueue(){return new Queue(RabbitMqConstants.MQ_MAIL_QUEUE,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete);}@Bean // 电话的队列public Queue phoneQueue(){return new Queue(RabbitMqConstants.MQ_PHONE_QUEUE,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete);}@Bean // 交换机public FanoutExchange fanoutExchange(){return new FanoutExchange(RabbitMqConstants.MQ_FANOUT_EXCHANGE,RabbitMqConstants.durable,RabbitMqConstants.autoDelete);}@Beanpublic Binding mailBinding(){return BindingBuilder.bind(mailQueue()).to(fanoutExchange());}@Beanpublic Binding phoneBinding(){return BindingBuilder.bind(phoneQueue()).to(fanoutExchange());}@Bean // A队列public Queue topicAQueue(){return new Queue(RabbitMqConstants.MQ_TOPIC_QUEUE_A,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete);}/*** topic模式相关配置*/@Bean // B队列public Queue topicBQueue(){return new Queue(RabbitMqConstants.MQ_TOPIC_QUEUE_B,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete);}@Bean // topic的交换机public TopicExchange topicMyExchange(){return new TopicExchange(RabbitMqConstants.MQ_TOPIC_EXCHANGE,RabbitMqConstants.durable,RabbitMqConstants.autoDelete);}@Beanpublic Binding topicAQueueBinding(){return BindingBuilder.bind(topicAQueue()).to(topicMyExchange()).with("topic.xxx"); // 规则 topic.xxx}@Beanpublic Binding topicBQueueBinding(){return BindingBuilder.bind(topicBQueue()).to(topicMyExchange()).with("topic.*"); // 规则 topic.xxx}}

生产者发送信息

在这里插入图片描述

    /*** topic模式下,生产者发送信息给交换机,可以决定给哪个队列发信息* @param msg 发送的信息* @param routingKey 类似正则表达式,决定给谁发*                   .with("topic.xxx"); // 规则 topic.xxx ---- A队列*                   .with("topic.*"); // 规则 topic.xxx   ---- B队列*                   在配置类中,如上所述配置,则如果输入的routingKey为 topic.xxx则给A和B发;*                                      如果输入的routingKey为 topic.yyy 则 只给B队列发;*/void sendMsg(String msg,String routingKey);

实现

package com.tianju.auth.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianju.auth.entity.UserPrivs;
import com.tianju.auth.mapper.UserMapper;
import com.tianju.auth.service.IUserService;
import com.tianju.auth.util.RabbitMqConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
@Slf4j
public class UserServiceImpl implements IUserService {@Autowiredprivate RabbitTemplate rabbitTemplate;@Overridepublic void sendCode(String msg) {rabbitTemplate.convertAndSend(RabbitMqConstants.MQ_FANOUT_EXCHANGE,"routingkey.fanout",msg);log.debug("[生产者向交换机:] 发送一条信息:{}",msg);}@Overridepublic void sendMsg(String msg,String routingKey) {rabbitTemplate.convertAndSend(RabbitMqConstants.MQ_TOPIC_EXCHANGE,routingKey, // "topic.yyy",此时只有B队列有信息msg);log.debug("[生产者向交换机:] 发送一条信息:{}",msg);}}

进行发送

package com.tianju.auth.service.impl;import cn.hutool.core.lang.Snowflake;
import com.tianju.auth.service.IUserService;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)public class UserServiceImplTest {@Autowiredprivate IUserService userService;@Testpublic void sendCode() {String code = new Snowflake().nextIdStr().substring(0, 6);System.out.println(code);userService.sendCode(code);}@Testpublic void sendTopic() {String code = new Snowflake().nextIdStr().substring(0, 6);System.out.println(code);userService.sendMsg(code,"topic.yyy");}
}

在这里插入图片描述

控制台查看

在这里插入图片描述

rabbitmq回调确认

配置类

spring:# rabbitmq的配置rabbitmq:host: 192.168.111.130port: 5672username: adminpassword: 123# 确认收到publisher-confirm-type: correlatedpublisher-returns: true

验证生产者发送是否成功

使用RabbitTemplate的回调方法。

先设置

  • setConfirmCallback
  • setReturnsCallback

在这里插入图片描述

    @Autowiredprivate RabbitTemplate rabbitTemplate;@Overridepublic void sendCode(String msg) {rabbitTemplate.convertAndSend(RabbitMqConstants.MQ_FANOUT_EXCHANGE,"routingkey.fanout",msg);log.debug("[生产者向交换机:] 发送一条信息:{}",msg);}@Overridepublic void sendMsg(String msg,String routingKey) {// 如果发到交换机,看一下有没有反馈rabbitTemplate.setConfirmCallback((c,ack,message)->{log.debug("***** setConfirmCallback:ack--{}", ack); // 是否发送到交换机log.debug("***** setConfirmCallback:c-->{}",c);// channel error; protocol method: #method<channel.close>(reply-code=404,// reply-text=NOT_FOUND - no exchange 'aaaa' in vhost '/', class-id=60, method-id=40)log.debug("***** setConfirmCallback:m-->{}",message);if (ack){log.debug("[生产者:] 发送信息到交换机{}","RabbitMqConstants.MQ_TOPIC_EXCHANGE");}else {log.debug(message);}});rabbitTemplate.setReturnsCallback(r->{log.debug("返回文字{}", r.getReplyText());log.debug("返回code{}", r.getReplyCode());log.debug("返回Exchange{}", r.getExchange());log.debug("返回RoutingKey{}", r.getRoutingKey());});rabbitTemplate.convertAndSend(RabbitMqConstants.MQ_TOPIC_EXCHANGE,
//                "aaaa",// 失败的情况routingKey, // "topic.yyy",此时只有B队列有信息msg);log.debug("[生产者向交换机:] 发送一条信息:{}",msg);}

在这里插入图片描述

rabbitTemplate.setConfirmCallback((c,ack,message)->{log.debug("******* setConfirmCallback:ack->{}",ack);log.debug("******* setConfirmCallback:c->{}",c);log.debug("******* setConfirmCallback:chanel->{}",message);if(ack){log.debug("[生产者]发送信息到达交换机{}","RabbitMqConstants.MQ_TOPIC_EXCHANGE");}else {log.debug(message);}
});
rabbitTemplate.setReturnsCallback(r->{log.debug("返回文字:{}",r.getReplyText());log.debug("返回code:{}",r.getReplyCode());log.debug("返回Exchange:{}",r.getExchange());log.debug("返回RoutingKey:{}",r.getRoutingKey());
});
rabbitTemplate.convertAndSend(RabbitMqConstants.MQ_TOPIC_EXCHANGE,"abc.xxx",msg
);
    @Testpublic void sendTopic() {String code = new Snowflake().nextIdStr().substring(0, 6);System.out.println(code);userService.sendMsg(code,"topic.rrr");}

延迟队列(死信)设计

Documentation: Table of Contents — RabbitMQ

在这里插入图片描述

在这里插入图片描述

java代码步骤

创建正常+死信队列

package com.tianju.mq.config;import com.tianju.mq.constants.RabbitMqConstants;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;@Configuration
public class RabbitMqConfig {@Beanpublic DirectExchange normalExchange(){return new DirectExchange(RabbitMqConstants.MQ_NORMAL_EXCHANGE,RabbitMqConstants.durable,RabbitMqConstants.autoDelete);}@Beanpublic Queue normalQueue(){Map<String, Object> map = new HashMap<>(2);map.put("x-dead-letter-exchange",RabbitMqConstants.MQ_DELAY_EXCHANGE);map.put("x-dead-letter-routing-key",RabbitMqConstants.MQ_DELAY_ROUTING_KEY);return new Queue(RabbitMqConstants.MQ_NORMAL_QUEUE,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete,map);}@Beanpublic Binding normalBinding(){return BindingBuilder.bind(normalQueue()).to(normalExchange()).with(RabbitMqConstants.MQ_NORMAL_ROUTING_KEY);}//------------------死信队列设计--------------------------/*** 死信(延迟)队列* @return*/@Beanpublic Queue delayQueue(){return new Queue(RabbitMqConstants.MQ_DELAY_QUEUE,RabbitMqConstants.durable,RabbitMqConstants.exclusive,RabbitMqConstants.autoDelete);}/*** 死信交换机* @return*/@Beanpublic DirectExchange delayExchange(){return new DirectExchange(RabbitMqConstants.MQ_DELAY_EXCHANGE,RabbitMqConstants.durable,RabbitMqConstants.autoDelete);}/*** 死信交换机队列绑定* @return*/@Beanpublic Binding delayBinding(){return BindingBuilder.bind(delayQueue()).to(delayExchange()).with(RabbitMqConstants.MQ_DELAY_ROUTING_KEY);}
}

配置类+常量

package com.tianju.mq.constants;public interface RabbitMqConstants {String MQ_DELAY_QUEUE = "mq_delay_queue"; // 延迟队列,死信队列String MQ_DELAY_EXCHANGE = "mq_delay_exchange"; // 死信交换机String MQ_DELAY_ROUTING_KEY = "mq_delay_routing_key"; // 死信路由// 正常的队列,交换机,路由String MQ_NORMAL_QUEUE = "mq_normal_queue";String MQ_NORMAL_EXCHANGE = "mq_normal_exchange";String MQ_NORMAL_ROUTING_KEY = "mq_normal_routing_key";// 参数boolean durable = true;boolean exclusive = false;boolean autoDelete = false;
}
server:port: 9099spring:# 邮箱的配置mail:host: smtp.qq.comport: 587username: xxxxx.compassword: xxxxx# rabbitmq的配置rabbitmq:host: 192.168.111.130port: 5672username: adminpassword: 123# 确认收到publisher-confirm-type: correlatedpublisher-returns: truelogging:level:com.tianju.mq: debug

生产者到正常队列

package com.tianju.mq.service;public interface IUserService {/*** 延迟队列的生产者* @param msg 发送的信息* @param delayTime 延迟的时间,毫秒*/void sendDelay(String msg,int delayTime);
}
package com.tianju.mq.service.impl;import com.tianju.mq.constants.RabbitMqConstants;
import com.tianju.mq.service.IUserService;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Date;@Service
@Slf4j
public class UserServiceImpl implements IUserService {@Autowiredprivate RabbitTemplate rabbitTemplate;@Overridepublic void sendDelay(String msg, int delayTime) {rabbitTemplate.convertAndSend(RabbitMqConstants.MQ_NORMAL_EXCHANGE,RabbitMqConstants.MQ_NORMAL_ROUTING_KEY,msg,process->{process.getMessageProperties().setExpiration(String.valueOf(delayTime));return process;});log.debug("[生产者:]发送消息:{},时间{},延迟{}秒",msg,new Date(),delayTime/1000);}
}

在这里插入图片描述

消费者进行延迟消费

package com.tianju.mq.consumer;import com.tianju.mq.constants.RabbitMqConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;import java.util.Date;@Service
@Slf4j
public class UserConsumer {@RabbitListener(queues = RabbitMqConstants.MQ_DELAY_QUEUE)public void delayConsume(String msg){log.debug("[消费者消费信息:{},时间:{}",msg,new Date());}
}

在这里插入图片描述

延迟队列插件安装

访问官网

Community Plugins — RabbitMQ

在这里插入图片描述

在这里插入图片描述

进入rabbitmq docker容器

[root@localhost ~]# docker exec -it rabbitmq bash

查询插件列表是否存在延迟插件

root@6d2342d51b11:/plugins# rabbitmq-plugins list
Listing plugins with pattern ".*" ...Configured: E = explicitly enabled; e = implicitly enabled| Status: * = running on rabbit@6d2342d51b11|/
[  ] rabbitmq_amqp1_0                  3.9.11
[  ] rabbitmq_auth_backend_cache       3.9.11
[  ] rabbitmq_auth_backend_http        3.9.11
[  ] rabbitmq_auth_backend_ldap        3.9.11
[  ] rabbitmq_auth_backend_oauth2      3.9.11
[  ] rabbitmq_auth_mechanism_ssl       3.9.11
[  ] rabbitmq_consistent_hash_exchange 3.9.11
[  ] rabbitmq_event_exchange           3.9.11
[  ] rabbitmq_federation               3.9.11
[  ] rabbitmq_federation_management    3.9.11
[  ] rabbitmq_jms_topic_exchange       3.9.11
[E*] rabbitmq_management               3.9.11
[e*] rabbitmq_management_agent         3.9.11
[  ] rabbitmq_mqtt                     3.9.11
[  ] rabbitmq_peer_discovery_aws       3.9.11
[  ] rabbitmq_peer_discovery_common    3.9.11
[  ] rabbitmq_peer_discovery_consul    3.9.11
[  ] rabbitmq_peer_discovery_etcd      3.9.11
[  ] rabbitmq_peer_discovery_k8s       3.9.11
[E*] rabbitmq_prometheus               3.9.11
[  ] rabbitmq_random_exchange          3.9.11
[  ] rabbitmq_recent_history_exchange  3.9.11
[  ] rabbitmq_sharding                 3.9.11
[  ] rabbitmq_shovel                   3.9.11
[  ] rabbitmq_shovel_management        3.9.11
[  ] rabbitmq_stomp                    3.9.11
[  ] rabbitmq_stream                   3.9.11
[  ] rabbitmq_stream_management        3.9.11
[  ] rabbitmq_top                      3.9.11
[  ] rabbitmq_tracing                  3.9.11
[  ] rabbitmq_trust_store              3.9.11
[e*] rabbitmq_web_dispatch             3.9.11
[  ] rabbitmq_web_mqtt                 3.9.11
[  ] rabbitmq_web_mqtt_examples        3.9.11
[  ] rabbitmq_web_stomp                3.9.11
[  ] rabbitmq_web_stomp_examples       3.9.11

下载支持3.9.x的插件

在这里插入图片描述

退出容器:

root@6d2342d51b11:/plugins# exit
exit

上传到linux服务器

在/usr/local/software/下创建文件夹rabbitmq/plugins

[root@localhost software]# mkdir -p rabbitmq/plugins

在这里插入图片描述

拷贝插件到容器中

[root@localhost plugins]# docker cp ./rabbitmq_delayed_message_exchange-3.9.0.ez rabbitmq:/plugins

进入容器安装插件

[root@localhost plugins]# docker  exec -it rabbitmq bash
root@6d2342d51b11:/# rabbitmq-plugins enable rabbitmq_delayed_message_exchange

打开管理页面

进入Exchange页面,下拉Type看是否已经安装成功。

在这里插入图片描述


总结

1.rabbitmq队列方式的梳理,点对点,一对多;
2.发布订阅模式,交换机到消费者,以邮箱和手机验证码为例;
3.topic模式,根据规则决定发送给哪个队列;
4.rabbitmq回调确认,setConfirmCallback和setReturnsCallback;
5.死信队列,延迟队列,创建方法,正常—死信,设置延迟时间;

相关文章:

RabbitMQ基础(2)——发布订阅/fanout模式 topic模式 rabbitmq回调确认 延迟队列(死信)设计

目录 引出点对点(simple)Work queues 一对多发布订阅/fanout模式以登陆验证码为例pom文件导包application.yml文件rabbitmq的配置生产者生成验证码&#xff0c;发送给交换机消费者消费验证码 topic模式配置类增加配置生产者发送信息进行发送控制台查看 rabbitmq回调确认配置类验…...

2. VisionOS平台概述

Unity 对VisionOS的支持将 Unity 编辑器和运行时引擎的全部功能与RealityKit提供的渲染功能结合起来。Unity 的核心功能&#xff08;包括脚本、物理、动画混合、AI、场景管理等&#xff09;无需修改即可支持。这允许游戏和应用程序逻辑像任何其他 Unity 支持的平台一样在Vision…...

MySql存储过程详解

文章目录 存储过程1 介绍 基本语法创建:调用查看删除演示: 变量相关系统变量演示: 用户自定义变量局部变量 if语法参数介绍casewhilerepeatloop游标条件处理程序存储函数 存储过程 1 介绍 存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合&#xff0c;调用存储过…...

CRM 系统实施风险分析

企业实施 CRM 系统将引起各个方面的巨大变化&#xff0c; CRM 系统实施项目中&#xff0c;有不 少成功的案例&#xff0c;也存在相当的风险&#xff0c;企业只有增强风险意识并积极防范&#xff0c;才有可能提高 CRM 实施成功的概率。 1.企业内部环境带来的风险 &#xff08;…...

保持城市天际线(力扣)贪心 JAVA

给你一座由 n x n 个街区组成的城市&#xff0c;每个街区都包含一座立方体建筑。给你一个下标从 0 开始的 n x n 整数矩阵 grid &#xff0c;其中 grid[r][c] 表示坐落于 r 行 c 列的建筑物的 高度 。 城市的 天际线 是从远处观察城市时&#xff0c;所有建筑物形成的外部轮廓。…...

电路综合原理与实践---T衰减与PI衰减的详细计算理论与设计仿真

电路综合原理与实践—T衰减与PI衰减的详细计算理论与设计仿真 最近要找工作在刷笔试题目&#xff0c;会刷到关于T衰减的理论计算问题&#xff0c;一直搞不明白怎么算的&#xff0c;搞明白之后给大家伙来分享一下。 基础理论可以参考&#xff1a;电阻衰减网络计算&#xff08;P…...

1. 基于UDP的TFTP文件传输

1&#xff09;tftp协议概述 简单文件传输协议&#xff0c;适用于在网络上进行文件传输的一套标准协议&#xff0c;使用UDP传输 特点&#xff1a; 是应用层协议 基于UDP协议实现 数据传输模式 octet&#xff1a;二进制模式&#xff08;常用&#xff09; mail&#xff1a;…...

django中使用bootstrap-datepicker时间插件

1、插件的下载 Bootstrap Datepicker是一款基 于Bootstrap框架的日期选择控件&#xff0c;可以方便地在Web应用中添加可交互的日期选择功能。Bootstrap Datepicker拥有丰富的选项和API,支持多种日期格式&#xff0c;可以自定义样式并支持各种语言。 Bootstrap Datepicker 依赖…...

《golang设计模式》第二部分·结构型模式-02-桥接模式(Bridge)

文章目录 1. 概念1.1 角色1.2 类图 2. 代码示例2.1 设计2.1 代码2.2 类图 1. 概念 客户端调用桥接接口实现原有功能和扩展功能的组合 1.1 角色 Implementor&#xff08;实施者&#xff09;&#xff1a; 具体实施者的抽象&#xff0c;可以是一个接口。 Concrete Implementor&…...

【2023年11月第四版教材】《第4章-信息系统管理之管理要点(第四版新增章节)(第二部分)》

信息系统管理之管理要点&#xff08;第四版新增章节&#xff09;&#xff08;第二部分&#xff09; 2 管理要点2.1 数据管理能力成熟度评估模型DCMM详细表格简要表格 2.2 组织的管理成熟度2.3 能力模型2.4 智能运维能力框架2.5 安全保护等级 2 管理要点 2.1 数据管理能力成熟度…...

【算法——双指针】LeetCode 1089 复写零

千万不要被这道题标注着“简单”迷惑了&#xff0c;实际上需要注意的细节很多。 题目描述&#xff1a; 解题思路&#xff1a; 正序遍历&#xff0c;确定结果数组的最后一个元素所在的位置&#xff1b;知道最后一个元素的位置后倒序进行填充。 先找到最后一个需要复写的数 先…...

基于飞桨图学习框架实现的城市地点动态关系挖掘

李双利 飞桨开发者技术专家&#xff08;PPDE&#xff09;&#xff0c;百度研究院商业智能实验室研究实习生&#xff0c;中国科学技术大学在读博士生。 主要进行时空数据挖掘和图深度学习的相关研究工作。曾获2021年百度研究院年度优秀实习生&#xff0c;有多篇基于飞桨完成的…...

3.1 Qt样式选择器

本期内容 3.1 样式选择器 3.1.1 Universal Selector (通用选择器) 3.1.2 Type Selector (类型选择器) 3.1.3 Property Selector (属性选择器) 3.1.4 Class Selector (类选择器) 3.1.5 ID Selector (ID选择器) 3.1.6 Descendant Selector (后裔选择器) 3.1.7 Chil…...

react钩子副作用理解

useEffect(() > { fetch(‘https://api.example.com/data’) .then(response > response.json()) .then(data > setData(data)); }, []); 怎么理解这个[] 在 React 中&#xff0c;useEffect 钩子用于处理副作用&#xff0c;比如数据获取、订阅、手动 DOM 操作等。useE…...

浅谈Spring与字节码生成技术

概要 今天来谈一谈我们熟知的Spring框架和字节码技术有什么联系。 Java程序员几乎都了解Spring。 它的IoC&#xff08;依赖反转&#xff09;和AOP&#xff08;面向切面编程&#xff09;功能非常强大、易用。而它背后的字节码生成技术&#xff08;在运行时&#xff0c;根据需要…...

时序预测 | MATLAB实现基于BiLSTM双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于BiLSTM双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于BiLSTM双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 Matlab实现BiLST…...

Flink多流处理之coGroup(协同分组)

这篇文章主要介绍协同分组coGroup的使用,先讲解API代码模板,后面会结图解介绍coGroup是如何将流中数据进行分组的. 1 API介绍 数据源# 左流数据 ➜ ~ nc -lk 6666 101,Tom 102,小明 103,小黑 104,张强 105,Ken 106,GG小日子 107,小花 108,赵宣艺 109,明亮# 右流数据 ➜ ~ n…...

基于TICK的DevOps监控实战(Ubuntu20.04系统,Telegraf+InfluDB+Chronograf+Kapacitor)

1、TICK简介 TICK是InfluxData开发的开源高性能时序中台&#xff0c;集成了采集、存储、分析、可视化等能力&#xff0c;由Telegraf, InfluDB, Chronograf, Kapacitor等4个组件以一种灵活松散、但又紧密配合&#xff0c;互为补充的方式构成。TICK专注于DevOps监控、IoT监控、实…...

十九、docker学习-Dockerfile

Dockerfile 官网地址 https://docs.docker.com/engine/reference/builder/Dockerfile其实就是我们用来构建Docker镜像的源码&#xff0c;当然这不是所谓的编程源码&#xff0c;而是一些命令的集合&#xff0c;只要理解它的逻辑和语法格式&#xff0c;就可以很容易的编写Docke…...

Docker容器的数据卷

1.数据卷的概念及作用 2.数据卷的配置 创建容器并挂载数据卷&#xff1a; docker run -it --namec1 -v /root/data:/root/data_container centos:7 /bin/bash按照容器挂载数据卷的原理&#xff0c;data_contianer这个目录下也会同步下来数据的更改。 3.一个容器挂载多个数据…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...