RabbitMQ学习——发布订阅/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 时,默认为 true 、 false 和 false 。表示持久化、非排它、不用自动删除。
创建交换机参数说明
| 参数 | 说明 |
|---|---|
| name | 字符串值,exchange 的名称。 |
| durable | 布尔值,表示该 exchage 是否持久化。 持久化意味着当 RabbitMQ 重启后,该 exchange 是否会恢复/仍存在。 |
| autoDelete | 布尔值,表示当该 exchange 没“人”(queue)用时,是否会被自动删除。 |
不指定 durable 和 autoDelete 时,默认为
true和false。表示持久化、不用自动删除
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: 826465890@qq.compassword: sdxgilesroqbbbje# 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学习——发布订阅/fanout模式 topic模式 rabbitmq回调确认 延迟队列(死信)设计
目录 引出点对点(simple)Work queues 一对多发布订阅/fanout模式以登陆验证码为例pom文件导包application.yml文件rabbitmq的配置生产者生成验证码,发送给交换机消费者消费验证码 topic模式配置类增加配置生产者发送信息进行发送控制台查看 rabbitmq回调确认配置类验…...
Leetcode算法递归类—合并两个有序链表
目录 21. 合并两个有序链表 题解: 代码: 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 输入:l1 [1,2,4], l2 [1,3,4] 输出:[1,1,2,3,4,4]示例 2&a…...
YOLOv5可视化界面
Pyside6可视化界面 安装Pyside6 激活之前的虚拟环境yolov5 在该环境的终端输入以下命令 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyside6输入where python找到当前使用的Python的路径 找到该路径下的designer.exe文件(/Lib/site-packages/PySi…...
C语言使用库函数实现大小写字母转换
功能;多行输入,输入大写字母,返回相应的小写字母;输入小写字母,返回相应的大写字母 需要用到的库函数: islower() -- 判断是否为小写,是,返回非0,…...
Redis简单学习
Redis是一个基于内存的key-value结构数据库 linux上面安装: Redis存储的是key-value结构的数据,其中key是字符串,value有常见的5中数据类型: 字符串 string哈希 hash列表 list集合 set有序集合 sorted set 字符串常用操作&am…...
《Python入门到精通》函数详解
「作者主页」:士别三日wyx 「作者简介」:CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」:小白零基础《Python入门到精通》 函数 1、函数的调用2、函数的参数2.1、变量的就近原则2.2、传递参数2.3、形参和实…...
PHP流浪动物招领网站mysql数据库web结构apache计算机软件工程网页wamp
一、源码特点 PHP流浪动物招领网站 是一套完善的web设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 下载链接 nullhttps://download.csdn.net/download/qq_41221322/88190168视频演示 …...
android—ktor-client封装使用,请求网络
ktor-client封装使用步骤: 1.导入依赖: 设置版本号: buildscript {ext.ktor_version 2.3.1 }添加依赖: implementation "io.ktor:ktor-client-okhttp:$ktor_version"implementation "io.ktor:ktor-client-auth…...
GD32F103VE侵入事件
GD32F103VE的TAMPER引脚(PC13),当PC13输入低电平时,会产生一个侵入检测事件。它会将所有“数据备份寄存器”内容清除。 这个功能有什么用? 一是防止被人开壳,抄袭。二是自毁功能。 直奔主题,多一句就是浪费时间。测试…...
将tp5项目、fastadmin项目部署到服务器宝塔面板
目录 一、将你的fastadmin或者tp5项目文件夹上传至你的服务器域名根目录下 二、修改你的网站目录指向,指向public目录,点击保存,并取消勾选防跨站攻击。 三、配置伪静态 四、fastadmin框架上传至服务器后如果想要访问后台可以进行重定向&am…...
Jenkins+Docker+SpringCloud微服务持续集成
JenkinsDockerSpringCloud微服务持续集成 JenkinsDockerSpringCloud持续集成流程说明SpringCloud微服务源码概述本地运行微服务本地部署微服务 Docker安装和Dockerfile制作微服务镜像Harbor镜像仓库安装及使用在Harbor创建用户和项目上传镜像到Harbor从Harbor下载镜像 微服务持…...
系统架构设计师-系统可靠性分析与设计
目录 一、可靠性相关基本概念 二、可靠性指标 1、串联系统与并联系统可靠性指标计算 2、混合系统 三、可靠性设计 1、影响软件可靠性的主要因素: 2、增加可靠性的解决方案 2.1 避错技术 2.2 降低复杂度设计 2.3 检错技术 2.4 容错技术 3、双机容错 一、可靠性相关…...
Linux(CentOS7)搭建达梦数据库
参考官方文档 本文记录一下达梦数据库的安装步骤,在安装的过程中出现了一些问题,进行了处理。 文章目录 安装前准备数据库安装命令行安装图形化安装 配置实例注册服务启动、停止数据库达梦数据库卸载 安装前准备 用户在安装 DM 数据库之前需要检查或修…...
[杂谈]-国产MCU竞争力浅析
[杂谈]-国产MCU竞争力浅析 文章目录 [杂谈]-国产MCU竞争力浅析1、研发方面2、技术方面3、市场方面4、应用方面5、生态方面6、总结 微控制器(MCU)是一种集成了微处理器、存储器、输入/输出接口和其他外设的单片电路,广泛应用于各种电子产品和系…...
4.1、Flink任务怎样读取集合中的数据
1、API说明 非并行数据源: def fromElements[T: TypeInformation](data: T*): DataStream[T] def fromCollection[T: TypeInformation](data: Seq[T]): DataStream[T] def fromCollection[T: TypeInformation] (data: Iterator[T]): Data…...
JD商品详情页面+关键词搜索商品列表API接口数据,详情页面数据返回值说明
作为一个工作助手,我无法直接为您提供实时的京东商品详情。您可以通过访问京东官方网站或使用API接口来查看商品的详细信息。每个商品的详情页面通常会包括以下内容: 1. 商品标题:商品的名称和简要描述。 2. 价格信息:包括原价、…...
Electron v26.0.0-beta.11 发布,跨平台桌面应用开发工具
Electron是一款跨平台桌面应用开发工具,它基于Web技术,使用HTML、CSS和JavaScript来构建应用程序。它能够让开发者使用熟悉的Web开发技术来创建强大的桌面应用,并且可以运行在Windows、macOS和Linux等多个操作系统上。 一、Electron的特点 跨平台:Electron可以将Web技术转…...
提高办案效率:公检系统引入自动校对技术
引入自动校对技术到公检系统中可以有效提高办案效率。自动校对技术结合公检系统的特点,可以在以下方面提高办案效率: 1.节省时间:自动校对技术可以快速检测和修正法律文书中的语法、拼写和标点符号等错误。与手动校对相比,自动校对…...
iptables 清空
清空 iptables中所有策略。 -Z: 重置计数器 -F:删除所有规则(flush) -X:删除所有自定义的链 规则清理和重建如下: iptables -Z iptables -t nat -F iptables -t nat -X iptables -t nat -P PREROUTING A…...
网络安全(黑客)零基础入门
导语 什么是 Web 安全?我又该如何入门学习它呢?学习过程中又应注意哪些问题呢?... 或许你的心中有着这样的疑问、不过别着急,本文会为你一一解答这些问题。 正文 定义 Web 安全,顾名思义便是由保障 Web 应用能够持续…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
