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

202527 | RabbitMQ-基础 | 队列 | Direct + Fanout + Topic 交换机 | 消息转换器

RabbitMQ

RabbitMQ 架构与核心概念详解


一、整体架构图
RabbitMQ Server
连接
存储
元数据
路由
路由
路由
发布消息
消费
消费
交换机
交换机
队列
队列
客户端应用
RabbitMQ Server
消息存储
元数据库
消费者
消费者

二、核心组件
组件作用类比现实
Producer消息生产者,将消息发送到交换机快递发货方
Exchange消息路由中心,根据规则将消息分发到队列快递分拣中心
Queue存储消息的缓冲区,先进先出快递暂存仓库
Consumer消息消费者,从队列获取消息处理快递收件人
Channel复用TCP连接的轻量级通信通道(减少TCP连接开销)快递运输专线
VHost虚拟主机,实现资源隔离(类似MySQL的database)独立物流园区
BrokerRabbitMQ服务实例整个物流公司

三、交换机类型(核心路由逻辑)
类型路由规则代码声明示例
Direct精确匹配routingKeychannel.exchangeDeclare("logs", "direct")
Fanout广播到所有绑定队列(忽略routingKeychannel.exchangeDeclare("alerts", "fanout")
Topic通配符匹配(*匹配1个词,#匹配0+个词)channel.exchangeDeclare("orders", "topic")
Headers根据消息头键值对匹配(性能差,少用)channel.exchangeDeclare("meta", "headers")

路由示例

// Topic交换机示例:路由订单相关消息
channel.basicPublish("orders", "order.create.us", null, message.getBytes());
// 匹配规则:order.*.us -> 匹配成功
// 匹配规则:order.# -> 匹配成功

四、消息流转全流程
Producer Exchange Queue Consumer Disk 发布消息(routingKey=order.pay) 根据绑定规则路由 消息持久化到磁盘 订阅消息(basicConsume) 推送消息 发送ACK确认 删除已确认消息 Producer Exchange Queue Consumer Disk

五、核心特性实现原理
  1. 消息持久化

    • 交换机/队列声明时设置durable=true
    • 消息设置deliveryMode=2
    channel.queueDeclare("orders", true, false, false, null); // 持久化队列
    channel.basicPublish("", "orders", MessageProperties.PERSISTENT_TEXT_PLAIN, // 持久化消息message.getBytes());
    
  2. ACK机制

    • 自动ACK(易丢失消息)
      channel.basicConsume(queue, true, consumer);
      
    • 手动ACK(推荐)
      channel.basicConsume(queue, false, (tag, delivery) -> {// 处理逻辑channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
      }, consumerTag -> {});
      
  3. QoS控制

    // 每次最多推送1条未ACK消息给消费者
    channel.basicQos(1);
    

六、高级特性架构
  1. 死信队列(DLX)

    消息超时/拒收
    主队列
    DLX交换机
    死信队列
    异常处理服务
    Map<String, Object> args = new HashMap<>();
    args.put("x-dead-letter-exchange", "dlx.exchange");
    channel.queueDeclare("orders", true, false, false, args);
    
  2. 延迟队列(插件实现)

    headers.put("x-delay", 60000); // 延迟60秒
    AMQP.BasicProperties props = new Builder().headers(headers).build();
    channel.basicPublish("delayed.exchange", "", props, message.getBytes());
    
  3. 集群架构

    镜像
    镜像
    镜像
    Node1
    Queue
    Node2
    Node3
    # 设置镜像策略
    rabbitmqctl set_policy ha-all "^ha\." '{"ha-mode":"all"}'
    

RabbitMQ 数据隔离详解

一、数据隔离的核心需求
45% 30% 15% 10% 数据隔离的应用场景 多租户环境 业务模块隔离 开发/测试/生产环境隔离 安全合规要求

二、RabbitMQ 数据隔离方案
1. VHost(虚拟主机)隔离

原理
每个VHost是独立的消息域,包含专属的交换机、队列和权限体系,类似MySQL的Database概念。

操作示例

# 创建VHost
rabbitmqctl add_vhost /order_service# 设置权限(用户order_user可访问)
rabbitmqctl set_permissions -p /order_service order_user ".*" ".*" ".*"# 删除VHost(慎用!会删除所有关联资源)
rabbitmqctl delete_vhost /order_service

Java连接配置

ConnectionFactory factory = new ConnectionFactory();
factory.setVirtualHost("/order_service");  // 关键隔离设置

特点

  • 不同VHost间完全隔离
  • 适用于多租户系统
  • 资源消耗极低(无需额外进程)

2. 用户权限控制

权限矩阵

权限类型命令示例作用范围
configure^order\.创建/删除队列/交换机
write^order\.发布消息到队列
read^order\.从队列消费消息

用户分级示例

# 管理员(全权限)
rabbitmqctl set_permissions -p /order_service admin ".*" ".*" ".*"# 生产者用户(只能写)
rabbitmqctl set_permissions -p /order_service producer "^order\..*" "" ""# 消费者用户(只能读)
rabbitmqctl set_permissions -p /order_service consumer "" "^order\..*" ""# 监控用户(只读)
rabbitmqctl set_permissions -p /order_service monitor "" "" ".*"

3. 队列命名规范隔离

命名规则示例

[业务域].[子系统].[功能]

实际案例

payment.notify.sms       # 支付短信通知队列
inventory.stock.update    # 库存更新队列
log.audit.tracking        # 审计日志队列

Java声明示例

// 支付业务队列
Map<String, Object> paymentArgs = new HashMap<>();
channel.queueDeclare("payment.transaction",  // 队列名true,                   // 持久化false,                  // 非排他false,                  // 非自动删除paymentArgs             // 扩展参数
);

4. 物理隔离(终极方案)

部署架构

金融专区集群
测试集群
生产集群
RabbitMQ Node2
RabbitMQ Node1
RabbitMQ Node2
RabbitMQ Node1
RabbitMQ Node2
RabbitMQ Node1

适用场景

  • 金融级数据隔离要求
  • 不同安全等级的业务
  • 合规性要求(如等保三级)

三、Spring Boot集成最佳实践
1. 多VHost配置
# application-order.yml
spring:rabbitmq:virtual-host: /order_service# application-payment.yml 
spring:rabbitmq:virtual-host: /payment_service
2. 动态路由选择
@Bean
public RabbitTemplate orderRabbitTemplate(@Qualifier("orderConnectionFactory") ConnectionFactory cf) {return new RabbitTemplate(cf);
}@Bean 
public ConnectionFactory orderConnectionFactory() {CachingConnectionFactory cf = new CachingConnectionFactory();cf.setVirtualHost("/order_service");return cf;
}
3. 监听器隔离
@RabbitListener(queues = "payment.notify",containerFactory = "secureContainerFactory")
public void handlePayment(Message message) {// 安全处理逻辑
}@Bean
public SimpleRabbitListenerContainerFactory secureContainerFactory() {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factory.setConnectionFactory(secureConnectionFactory());factory.setConsumerTagStrategy(queue -> "secure_" + UUID.randomUUID());return factory;
}

四、监控与运维要点
1. 隔离资源监控
# 查看各VHost资源占用
rabbitmqctl list_vhosts name messages messages_ready messages_unacknowledged# 输出示例
/order_service    0       0       0
/payment_service  125     80      45
2. 权限审计命令
# 查看用户权限
rabbitmqctl list_permissions -p /order_service# 查看用户标签
rabbitmqctl list_users
3. 故障排查流程
正确
错误
消息无法路由
检查VHost配置
检查交换机/队列绑定
修正连接参数
验证routingKey匹配
检查消费者状态

五、不同方案的选型建议
方案隔离强度性能影响适用场景
VHost隔离★★★★多业务模块/多环境隔离
用户权限控制★★☆内部系统角色隔离
队列命名规范★☆☆开发规范辅助
物理集群隔离★★★★★高成本金融/政务等高安全要求

黄金法则
80%的场景使用 VHost+权限控制 即可满足需求,剩余20%的特殊场景考虑物理隔离。

Spring Boot 集成 RabbitMQ 极简指南

一、3步快速集成
1. 添加依赖
<!-- pom.xml -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2. 配置连接
# application.yml
spring:rabbitmq:host: localhostport: 5672username: guestpassword: guestvirtual-host: /
3. 发送/接收消息
@RestController
public class DemoController {@Autowiredprivate RabbitTemplate rabbitTemplate;// 发送消息@GetMapping("/send")public String send(@RequestParam String msg) {rabbitTemplate.convertAndSend("demo.queue", msg);return "Sent: " + msg;}// 接收消息@RabbitListener(queues = "demo.queue")public void receive(String msg) {System.out.println("Received: " + msg);}
}
二、核心组件说明
组件作用示例代码
RabbitTemplate消息发送工具convertAndSend("队列名",消息)
@RabbitListener消息监听注解@RabbitListener(queues="队列名")
AmqpAdmin队列/交换机管理declareQueue(new Queue("q1"))
三、高级配置示例**
1. 手动创建队列
@Configuration
public class RabbitConfig {@Beanpublic Queue demoQueue() {return new Queue("demo.queue", true); // 持久化队列}
}
2. 发送复杂对象
// 发送端
rabbitTemplate.convertAndSend("demo.queue", new Order(1001L));// 接收端
@RabbitListener(queues = "demo.queue")
public void handleOrder(Order order) {// 处理订单对象
}

提示:对象需实现Serializable接口

四、常用注解速查**
注解作用
@RabbitListener声明消息监听器
@RabbitHandler多方法处理不同类型消息
@QueueBinding绑定队列到交换机

RabbitMQ Work Queues 详解

一、核心概念

Work Queues(工作队列)是RabbitMQ最基础的消息模式,主要用于任务分发。其核心特点是:

  1. 一个生产者多个消费者共同消费同一个队列
  2. 消息采用轮询分发(Round-robin)策略
  3. 适合异步处理耗时任务(如图片处理、邮件发送等)
Task 1,2,3
Producer
Task Queue
Worker1
Worker2
Worker3
二、与简单队列的区别
特性简单队列工作队列
消费者数量1个多个
消息分发全部发给单个消费者轮询分发给所有消费者
典型应用场景简单消息传递并行任务处理
三、Java实现(Spring Boot版)
1. 生产者代码
@RestController
public class TaskController {@Autowiredprivate RabbitTemplate rabbitTemplate;@GetMapping("/send-task")public String sendTask(@RequestParam String task) {// 发送到名为"task_queue"的队列rabbitTemplate.convertAndSend("task_queue", task);return "Task sent: " + task;}
}
2. 消费者代码
@Component
public class TaskWorker {@RabbitListener(queues = "task_queue")public void processTask(String task) throws InterruptedException {System.out.println(" [x] Processing: " + task);// 模拟耗时操作Thread.sleep(1000); System.out.println(" [x] Completed: " + task);}
}
3. 队列配置(可选)
@Configuration
public class RabbitConfig {@Beanpublic Queue taskQueue() {return new Queue("task_queue", true); // 持久化队列}
}
四、关键特性
1. 消息确认(ACK机制)
@RabbitListener(queues = "task_queue")
public void processTask(String task, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {try {// 业务处理...channel.basicAck(tag, false); // 手动确认} catch (Exception e) {channel.basicNack(tag, false, true); // 失败重试}
}
2. 公平分发(Prefetch)
# application.yml
spring:rabbitmq:listener:simple:prefetch: 1 # 每次只给消费者1条未ACK的消息
3. 消息持久化
// 发送持久化消息
rabbitTemplate.convertAndSend("task_queue", MessageBuilder.withBody(task.getBytes()).setDeliveryMode(MessageDeliveryMode.PERSISTENT).build());
五、工作流程示例
  1. 发送3个任务:
    curl http://localhost:8080/send-task?task=Task1
    curl http://localhost:8080/send-task?task=Task2
    curl http://localhost:8080/send-task?task=Task3
    
  2. 启动2个消费者实例
  3. 观察控制台输出:
    Worker1: Processing Task1
    Worker2: Processing Task2
    Worker1: Processing Task3
    
六、生产环境建议
  1. 始终启用消息持久化
    • 队列持久化
    • 消息持久化
  2. 合理设置prefetch
    • CPU密集型任务:prefetch=1~5
    • IO密集型任务:prefetch=10~50
  3. 实现死信队列处理失败消息
七、管理界面监控

访问 http://localhost:15672 查看:

  • Queues 标签页:
    • Ready:待处理消息数
    • Unacked:正在处理的消息数
    • Total:消息总数

RabbitMQ Direct交换机深度解析

一、核心本质

Direct交换机是精确路由器,根据消息的routing key完全匹配队列绑定键,实现点对点精准投递。其核心特征:

  1. 严格匹配routing key必须等于binding key
  2. 单队列投递:每条消息只会路由到一个队列(除非重复绑定)
  3. 高性能:哈希表实现O(1)复杂度路由
routingKey=payments
精确匹配
匹配失败
Producer
Direct Exchange
payments
orders
支付服务
二、三大核心特性
特性说明与Fanout/Topic对比
精确路由全等匹配routing keyFanout不检查key,Topic支持通配符
单点投递消息只会进入一个匹配队列(除非多队列同binding key)Fanout广播到所有队列
路由高效哈希表直接查找Topic需要模式匹配,性能略低
三、Spring Boot实战示例
1. 声明配置(Java Config)
@Configuration
public class DirectConfig {// 声明直连交换机@Beanpublic DirectExchange orderExchange() {return new DirectExchange("order.direct"); }// 声明业务队列@Beanpublic Queue paymentQueue() { return new Queue("payment"); }@Bean public Queue stockQueue() {return new Queue("stock"); }// 绑定队列到交换机(指定binding key)@Beanpublic Binding bindPayment(DirectExchange orderExchange, Queue paymentQueue) {return BindingBuilder.bind(paymentQueue).to(orderExchange).with("pay"); // binding key}@Beanpublic Binding bindStock(DirectExchange orderExchange, Queue stockQueue) {return BindingBuilder.bind(stockQueue).to(orderExchange).with("stock.update");}
}
2. 生产者发送(指定routing key)
@Service
public class OrderService {@Autowiredprivate RabbitTemplate rabbitTemplate;public void processPayment(Long orderId) {// routing key必须与binding key完全匹配rabbitTemplate.convertAndSend("order.direct", "pay", new PaymentEvent(orderId, "SUCCESS"));}public void updateStock(Long skuId, int num) {// 匹配stock.update队列rabbitTemplate.convertAndSend("order.direct", "stock.update",Map.of("skuId", skuId, "delta", num));}
}
3. 消费者监听
@Component
public class OrderListener {// 支付结果处理@RabbitListener(queues = "payment")public void handlePayment(PaymentEvent event) {paymentService.confirm(event.getOrderId());}// 库存更新处理@RabbitListener(queues = "stock")public void handleStockUpdate(@Payload Map<String, Object> data) {stockService.adjust((Long)data.get("skuId"), (Integer)data.get("delta"));}
}
四、路由匹配规则详解
场景routing keybinding key是否匹配
完全匹配paypay
大小写敏感Paypay
多队列同binding keyalertalert(队列A)同时投递A/B
alert(队列B)
不同binding keyorder.createorder.pay
五、高级应用场景
1. 多消费者负载均衡
routingKey=log
P
Direct
log
Consumer1
Consumer2
// 两个消费者实例监听同一队列
@RabbitListener(queues = "log")
public class LogConsumer1 { /* ... */ }@RabbitListener(queues = "log")
public class LogConsumer2 { /* ... */ }
2. 优先级队列
@Bean
public Queue priorityQueue() {Map<String, Object> args = new HashMap<>();args.put("x-max-priority", 10); // 设置优先级范围return new Queue("priority.queue", true, false, false, args);
}// 发送优先级消息
rabbitTemplate.convertAndSend("exchange", "key", message, m -> {m.getMessageProperties().setPriority(5); // 设置优先级return m;
});
3. 死信路由
@Bean
public Queue workQueue() {Map<String, Object> args = new HashMap<>();args.put("x-dead-letter-exchange", "dlx.direct");args.put("x-dead-letter-routing-key", "dead");return new Queue("work.queue", true, false, false, args);
}
六、性能优化方案
  1. 批量绑定声明
@Bean
public Declarables bindingBatch() {return new Declarables(new DirectExchange("batch.direct"),new Queue("q1"),new Queue("q2"),BindingBuilder.bind("q1").to("batch.direct").with("key1"),BindingBuilder.bind("q2").to("batch.direct").with("key2"));
}
  1. 路由键哈希优化
// 使用一致性哈希路由
@Bean
public Exchange hashedExchange() {Map<String, Object> args = new HashMap<>();args.put("hash-header", "routing-key"); // 指定哈希字段return new DirectExchange("hashed.direct", true, false, args);
}
  1. 监控路由命中
rabbitmqctl list_bindings source_name routing_key destination_name
七、常见问题解决方案

问题1:消息路由失败怎么办?

// 启用mandatory模式捕获未路由消息
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnsCallback(returned -> {log.error("消息未路由: {}", returned.getMessage());
});

问题2:需要多重条件匹配?

// 改用Topic交换机
rabbitTemplate.convertAndSend("order.topic", "pay.wechat", message);

问题3:如何实现延迟重试?

// 组合使用DLX+TTL
args.put("x-dead-letter-exchange", "retry.direct");
args.put("x-message-ttl", 5000); // 5秒后重试

Direct交换机是RabbitMQ中最简单高效的路由方案,适用于需要精确控制消息去向的场景。当你的业务需要明确的"一对一"消息路由时,Direct交换机永远是最可靠的选择。

RabbitMQ Fanout交换机详解

一、核心特性

Fanout交换机是RabbitMQ中最简单的广播型交换机,其核心特点是:

  1. 无条件广播:将消息发送到所有绑定队列,完全忽略Routing Key
  2. 一对多分发:每个绑定队列都会收到消息的完整副本
  3. 零过滤逻辑:不执行任何路由匹配计算
发布消息
复制分发
复制分发
复制分发
生产者
Fanout交换机
邮件队列
短信队列
APP推送队列
邮件服务
短信服务
推送服务
二、与Direct/Topic交换机的区别
特性FanoutDirectTopic
路由依据精确匹配Routing Key通配符匹配Routing Key
消息去向所有绑定队列单个匹配队列多个匹配队列
性能最高中等
典型场景系统通知、事件广播订单支付、库存扣减多条件消息路由
三、Spring Boot实战实现
1. 声明交换机和队列(配置类)
@Configuration
public class FanoutConfig {// 定义广播交换机@Beanpublic FanoutExchange notificationExchange() {return new FanoutExchange("notify.fanout"); }// 定义三个业务队列@Beanpublic Queue emailQueue() {return new Queue("notify.email"); }@Bean public Queue smsQueue() {return new Queue("notify.sms"); }@Beanpublic Queue appQueue() {return new Queue("notify.app");}// 绑定队列到交换机(无需指定路由键)@Beanpublic Binding bindEmail(FanoutExchange notificationExchange, Queue emailQueue) {return BindingBuilder.bind(emailQueue).to(notificationExchange);}@Beanpublic Binding bindSms(FanoutExchange notificationExchange, Queue smsQueue) {return BindingBuilder.bind(smsQueue).to(notificationExchange);}@Beanpublic Binding bindApp(FanoutExchange notificationExchange, Queue appQueue) {return BindingBuilder.bind(appQueue).to(notificationExchange);}
}
2. 消息生产者(Controller示例)
@RestController
public class NotificationController {@Autowiredprivate RabbitTemplate rabbitTemplate;@PostMapping("/broadcast")public String sendAlert(@RequestBody String message) {// 发送到fanout交换机(第二个参数routing key被忽略)rabbitTemplate.convertAndSend("notify.fanout", "", MessageBuilder.withBody(message.getBytes()).setHeader("alert-level", "URGENT") // 添加消息头.build());return "广播消息已发送: " + message;}
}
3. 消息消费者(监听器示例)
@Component
public class NotificationListener {// 邮件服务消费者@RabbitListener(queues = "notify.email")public void handleEmail(String message, @Header("alert-level") String level) {System.out.printf("[邮件][%s] %s%n", level, message);}// 短信服务消费者@RabbitListener(queues = "notify.sms")public void handleSms(Message message) throws IOException {String content = new String(message.getBody());System.out.println("[短信] " + content);}// APP推送消费者@RabbitListener(queues = "notify.app")public void handleAppPush(String message, Channel channel,@Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {try {pushService.sendToAll(message);channel.basicAck(tag, false); // 手动确认} catch (Exception e) {channel.basicNack(tag, false, true); // 失败重试}}
}
四、高级应用场景
1. 微服务配置刷新
// 配置中心发送刷新命令
public void refreshAllServices() {rabbitTemplate.convertAndSend("config.fanout", "", new ConfigRefreshEvent("ALL", Instant.now()));
}// 各微服务监听(每个服务有自己的队列)
@RabbitListener(queues = "#{configQueue.name}")
public void handleRefresh(ConfigRefreshEvent event) {if ("ALL".equals(event.getScope()) || serviceName.equals(event.getScope())) {configManager.refresh();}
}
2. 分布式日志收集
日志事件
日志事件
日志事件
服务A
logs.fanout
服务B
服务C
ES存储队列
报警分析队列
归档备份队列
3. 实时数据同步
// 数据库变更时广播事件
@TransactionalEventListener
public void handleDataChange(DataChangeEvent event) {rabbitTemplate.convertAndSend("data.sync.fanout", "", event);
}// 多个子系统同步处理
@RabbitListener(queues = "cache.update.queue")
public void syncCache(DataChangeEvent event) {cache.evict(event.getKey());
}
五、生产环境注意事项
  1. 消息堆积预防

    # 限制队列最大长度
    spring:rabbitmq:listener:simple:prefetch: 50 # 每个消费者预取数量
    
    @Bean
    public Queue limitedQueue() {Map<String, Object> args = new HashMap<>();args.put("x-max-length", 10000); // 队列最大消息数return new Queue("limited.queue", true, false, false, args);
    }
    
  2. 监控关键指标

    # 查看消息分发状态
    rabbitmqctl list_queues name messages_ready messages_unacknowledged# 查看交换机绑定
    rabbitmqctl list_bindings source_name destination_name
    
  3. 异常处理方案

    // 全局异常处理器
    @RabbitListener(queues = "notify.email", errorHandler = "emailErrorHandler")
    public void processEmail(String message) {emailService.send(message);
    }@Bean
    public RabbitListenerErrorHandler emailErrorHandler() {return (msg, ex) -> {log.error("邮件发送失败: {}", msg.getPayload(), ex);// 记录失败消息到DBfailoverService.save(msg.getPayload()); return null;};
    }
    
六、性能优化技巧
  1. 消息压缩

    rabbitTemplate.setBeforePublishPostProcessors(message -> {if (message.getBody().length > 1024) {message.getMessageProperties().setContentEncoding("gzip");return new GZipPostProcessor().process(message);}return message;
    });
    
  2. 批量绑定声明

    @Bean
    public Declarables fanoutBindings() {FanoutExchange exchange = new FanoutExchange("batch.fanout");return new Declarables(exchange,new Queue("batch.q1"),new Queue("batch.q2"),BindingBuilder.bind(new Queue("batch.q1")).to(exchange),BindingBuilder.bind(new Queue("batch.q2")).to(exchange));
    }
    
  3. 多消费者并发

    spring:rabbitmq:listener:simple:concurrency: 5 # 每个监听器启动5个消费者线程
    

Fanout交换机是RabbitMQ中最简单直接的广播机制,适用于需要一对多消息分发不关心路由逻辑的场景。当您需要确保多个系统接收完全相同的信息副本时,Fanout交换机是最可靠的选择。

RabbitMQ Topic交换机

一、核心特性

Topic交换机是智能路由器,通过routing key通配符匹配实现灵活的消息分发。核心特点:

  1. 模式匹配:支持*(匹配一个词)和#(匹配零或多个词)
  2. 多队列投递:一条消息可同时路由到多个匹配队列
  3. 动态路由:绑定关系可随时变更,不影响生产者
routingKey=order.payment.wechat
匹配*.payment.*
匹配order.#
匹配#.wechat
Producer
Topic Exchange
支付队列
订单队列
微信队列
支付服务
订单服务
微信服务
二、与Direct/Fanout交换机的区别
特性TopicDirectFanout
路由精度通配符匹配精确匹配无匹配
消息去向多个匹配队列单个匹配队列所有绑定队列
灵活性高(动态路由)中(固定路由)低(仅广播)
典型场景多条件事件分发点对点任务系统广播
三、通配符规则详解
通配符含义示例匹配示例
*匹配一个单词order.*.payorder.wechat.pay
#匹配零或多个单词log.#.errorlog.app.error / log.error
.单词分隔符china.beijing必须严格包含分隔符

特殊案例

  • usa.# 可匹配 usausa.nyc.weather
  • *.temp 不匹配 temp(必须有一个前置单词)
四、Spring Boot实战实现
1. 声明交换机和队列(配置类)
@Configuration
public class TopicConfig {// 定义Topic交换机@Beanpublic TopicExchange eventExchange() {return new TopicExchange("events.topic"); }// 定义业务队列@Beanpublic Queue paymentQueue() {return new Queue("payment.events"); }@Bean public Queue orderQueue() {return new Queue("order.events"); }@Beanpublic Queue logQueue() {return new Queue("system.log");}// 绑定队列到交换机(指定通配符)@Beanpublic Binding bindPayment(TopicExchange eventExchange, Queue paymentQueue) {return BindingBuilder.bind(paymentQueue).to(eventExchange).with("*.payment.*"); // 匹配如: wechat.payment.success}@Beanpublic Binding bindOrder(TopicExchange eventExchange, Queue orderQueue) {return BindingBuilder.bind(orderQueue).to(eventExchange).with("order.#"); // 匹配如: order.create/order.cancel}@Beanpublic Binding bindLog(TopicExchange eventExchange, Queue logQueue) {return BindingBuilder.bind(logQueue).to(eventExchange).with("#.error"); // 匹配如: db.error/app.error}
}
2. 消息生产者(Service示例)
@Service
public class EventPublisher {@Autowiredprivate RabbitTemplate rabbitTemplate;// 支付成功事件public void publishPaymentSuccess(String channel) {String routingKey = channel + ".payment.success";rabbitTemplate.convertAndSend("events.topic", routingKey, new PaymentEvent(channel, "SUCCESS"));}// 订单状态变更public void publishOrderEvent(String action) {rabbitTemplate.convertAndSend("events.topic", "order." + action,  // 如: order.createnew OrderEvent(action));}// 系统错误日志public void publishErrorLog(String module) {rabbitTemplate.convertAndSend("events.topic", module + ".error",  // 如: db.errornew ErrorLog(module));}
}
3. 消息消费者(监听器示例)
@Component
public class EventListener {// 处理所有支付事件@RabbitListener(queues = "payment.events")public void handlePayment(PaymentEvent event) {paymentService.process(event);}// 处理所有订单事件@RabbitListener(queues = "order.events")public void handleOrderEvent(OrderEvent event, @Header(AmqpHeaders.RECEIVED_ROUTING_KEY) String key) {log.info("收到订单事件[{}]: {}", key, event);orderService.handle(event.getAction());}// 处理所有错误日志@RabbitListener(queues = "system.log")public void handleErrorLog(ErrorLog log) {alertService.notifyAdmin(log);logService.archive(log);}
}
五、高级应用场景
1. 多维度消息路由
routingKey=order.eu.payment
匹配 order.*.payment
匹配 order.eu.#
匹配 *.payment
P
Topic Exchange
支付队列
欧洲订单队列
全局支付队列
2. 动态绑定调整
// 运行时添加新路由
public void addNewRoute(String serviceName) {Queue queue = new Queue(serviceName + ".queue");Binding binding = BindingBuilder.bind(queue).to(topicExchange).with(serviceName + ".#");rabbitAdmin.declareBinding(binding);
}
3. 多级日志处理
// 发送不同级别日志
public void log(String module, String level, String msg) {String routingKey = module + "." + level; // 如: auth.warningrabbitTemplate.convertAndSend("logs.topic", routingKey, msg);
}// 监听不同级别
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "critical.log"),exchange = @Exchange(name = "logs.topic"),key = "#.critical" // 监听所有critical日志
))
public void handleCriticalLog(String log) {alertService.notifyOnCall(log);
}
六、性能优化方案
  1. 路由键设计原则

    // 推荐分层结构
    "区域.业务.动作"  // 如: eu.order.payment
    "模块.级别"      // 如: auth.error
    
  2. 绑定缓存优化

    spring:rabbitmq:cache:connection:mode: CONNECTION # 复用连接提高绑定查询效率
    
  3. 监控路由性能

    # 查看交换机消息统计
    rabbitmqctl list_exchanges name message_stats.publish_in message_stats.publish_out
    
七、常见问题解决方案

问题1:通配符匹配失效?

// 检查单词分隔符
String validKey = "china.beijing"; // 正确
String invalidKey = "china_beijing"; // 无法匹配china.*

问题2:需要更复杂的路由逻辑?

// 组合使用Header交换机
Map<String, Object> headers = new HashMap<>();
headers.put("region", "asia");
headers.put("priority", "high");
rabbitTemplate.convertAndSend("headers.ex", "", msg, m -> { m.getMessageProperties().setHeaders(headers); return m; });

问题3:如何实现灰度发布?

// 通过路由键版本控制
String routingKey = "v2.order.create"; 
if (isGrayUser(userId)) {rabbitTemplate.convertAndSend("orders.topic", routingKey, order);
}

Topic交换机是RabbitMQ中最灵活的智能路由器,特别适合需要多维度消息分发的场景。当您的业务需要根据多种条件动态路由消息时,Topic交换机的通配符匹配能力将成为最佳选择。

RabbitMQ 队列与交换机声明


一、按声明时机分类
类型执行阶段特点适用场景
静态声明应用启动时配置集中,易于管理固定拓扑结构
动态声明运行时灵活调整拓扑多租户/动态路由需求
混合声明启动时+运行时兼顾稳定性和灵活性核心业务+扩展功能

二、按技术实现分类
1. Spring AMQP注解方式
// 声明队列+交换机+绑定(三合一)
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "alert.queue",durable = "true",arguments = @Argument(name = "x-max-length", value = "1000")),exchange = @Exchange(name = "alert.exchange",type = ExchangeTypes.TOPIC),key = "alert.#"
))
public void handleAlert(AlertMessage message) {// 消息处理逻辑
}

优点:声明与消费代码一体,简洁
缺点:无法复用声明配置
适用:简单业务场景

2. Java Config配置类
@Configuration
public class RabbitDeclareConfig {// 声明持久化Topic交换机@Beanpublic TopicExchange orderExchange() {return new TopicExchange("order.topic", true, false);}// 声明带死信队列的订单队列@Beanpublic Queue orderQueue() {Map<String, Object> args = new HashMap<>();args.put("x-dead-letter-exchange", "dlx.order");args.put("x-max-priority", 10);return new Queue("order.queue", true, false, false, args);}// 批量声明(优化性能)@Beanpublic Declarables businessBindings() {Queue q1 = new Queue("inventory.queue");Queue q2 = new Queue("payment.queue");TopicExchange exchange = new TopicExchange("business.exchange");return new Declarables(exchange, q1, q2,BindingBuilder.bind(q1).to(exchange).with("stock.*"),BindingBuilder.bind(q2).to(exchange).with("pay.#"));}
}

优点:配置集中管理,支持复杂参数
缺点:代码量较大
适用:生产环境推荐方案

3. RabbitMQ管理API
@Autowired
private AmqpAdmin amqpAdmin;// 动态创建延迟队列
public void createDelayQueue(String queueName, long ttl) {Map<String, Object> args = new HashMap<>();args.put("x-message-ttl", ttl);args.put("x-dead-letter-exchange", "processed.exchange");amqpAdmin.declareQueue(new Queue(queueName, true, false, false, args));// 动态绑定Binding binding = new Binding(queueName,Binding.DestinationType.QUEUE,"delay.exchange","delay.key",null);amqpAdmin.declareBinding(binding);
}

优点:运行时灵活控制
缺点:需处理异常情况
适用:灰度发布、多租户系统

4. 管理界面手动操作

步骤

  1. 访问 http://localhost:15672
  2. 进入 QueuesExchanges 标签页
  3. 点击 Add a new queue/exchange
  4. 填写参数并保存

优点:可视化即时生效
缺点:难以版本控制
适用:开发测试环境调试


三、按消息模式分类
1. 简单队列模式
// 无需交换机(使用默认交换机)
@Bean
public Queue simpleQueue() {return new Queue("simple.queue");
}
2. 工作队列模式
@Bean
public Queue workQueue() {return new Queue("work.queue", true); // 持久化
}// 多个消费者监听同一队列实现负载均衡
@RabbitListener(queues = "work.queue", concurrency = "3")
public void worker(Message message) {// 处理任务
}
3. 发布/订阅模式
@Bean
public FanoutExchange pubSubExchange() {return new FanoutExchange("broadcast.exchange");
}@Bean
public Queue subQueue1() {return new Queue("sub.queue1");
}@Bean
public Binding binding1(FanoutExchange pubSubExchange, Queue subQueue1) {return BindingBuilder.bind(subQueue1).to(pubSubExchange);
}
4. 路由模式
@Bean
public DirectExchange routingExchange() {return new DirectExchange("routing.exchange");
}@Bean
public Binding errorBinding(DirectExchange routingExchange, Queue errorQueue) {return BindingBuilder.bind(errorQueue).to(routingExchange).with("error"); // 精确匹配routing key
}
5. 主题模式
@Bean
public TopicExchange topicExchange() {return new TopicExchange("topic.exchange");
}@Bean
public Binding auditBinding(TopicExchange topicExchange, Queue auditQueue) {return BindingBuilder.bind(auditQueue).to(topicExchange).with("*.audit.#"); // 通配符匹配
}

四、按业务场景分类
1. 订单系统
@Bean
public TopicExchange orderExchange() {return new TopicExchange("order.topic", true, false);
}@Bean
public Queue orderCreateQueue() {Map<String, Object> args = new HashMap<>();args.put("x-max-priority", 10); // 支持优先级return new Queue("order.create", true, false, false, args);
}@Bean
public Binding orderCreateBinding() {return BindingBuilder.bind(orderCreateQueue()).to(orderExchange()).with("order.create");
}
2. 日志收集
@Bean
public FanoutExchange logExchange() {return new FanoutExchange("log.fanout");
}@Bean
public Queue esLogQueue() {return new Queue("log.es", true);
}@Bean
public Binding esLogBinding() {return BindingBuilder.bind(esLogQueue()).to(logExchange());
}
3. 延迟任务
@Bean
public CustomExchange delayExchange() {Map<String, Object> args = new HashMap<>();args.put("x-delayed-type", "direct");return new CustomExchange("delay.exchange", "x-delayed-message", true, false, args);
}@Bean
public Queue delayQueue() {return new Queue("delay.queue", true);
}@Bean
public Binding delayBinding() {return BindingBuilder.bind(delayQueue()).to(delayExchange()).with("delay.key").noargs();
}

五、高级特性配置
1. 死信队列
@Bean
public Queue businessQueue() {Map<String, Object> args = new HashMap<>();args.put("x-dead-letter-exchange", "dlx.exchange");args.put("x-dead-letter-routing-key", "dlx.key");args.put("x-message-ttl", 60000); // 1分钟TTLreturn new Queue("business.queue", true, false, false, args);
}
2. 惰性队列
@Bean
public Queue lazyQueue() {Map<String, Object> args = new HashMap<>();args.put("x-queue-mode", "lazy"); // 节省内存return new Queue("lazy.queue", true, false, false, args);
}
3. 优先级队列
@Bean
public Queue priorityQueue() {Map<String, Object> args = new HashMap<>();args.put("x-max-priority", 5); // 支持5个优先级return new Queue("priority.queue", true, false, false, args);
}

六、声明策略最佳实践
  1. 生产环境标配

    @Bean
    public Queue productionQueue() {return new Queue("prod.queue", true,   // durablefalse,  // exclusivefalse,  // autoDeleteMap.of( // arguments"x-max-length", 5000,"x-overflow", "reject-publish","x-queue-mode", "lazy"));
    }
    
  2. 开发环境简化

    @Profile("dev")
    @Bean
    public Queue devQueue() {return new Queue("dev.queue", false, true, true); // 临时队列
    }
    
  3. 灰度发布方案

    public void declareGrayQueue(String version) {Queue queue = new Queue("order." + version);Binding binding = new Binding(queue.getName(),Binding.DestinationType.QUEUE,"order.exchange","order." + version,null);amqpAdmin.declareQueue(queue);amqpAdmin.declareBinding(binding);
    }
    

通过这种结构化分类,您可以根据具体业务需求快速选择最适合的声明方式。建议:

  1. 核心业务:采用Java Config静态声明
  2. 动态需求:结合AmqpAdmin API
  3. 特殊场景:使用注解简化开发
  4. 生产环境:务必配置持久化、长度限制等保护参数

RabbitMQ 消息转换器

一、消息转换器的核心作用

消息转换器(Message Converter)是Spring AMQP中用于Java对象与消息体相互转换的组件,主要处理:

  1. 序列化:将Java对象转为MQ可传输的字节流
  2. 反序列化:将MQ消息体还原为Java对象
  3. 内容协商:根据Content-Type处理不同数据格式
序列化
反序列化
Java对象
Message Body
Java对象
二、Spring AMQP内置转换器对比
转换器类型依赖库特点适用场景
SimpleMessageConverter支持String/byte[]/Serializable基础类型传输
Jackson2JsonMessageConverterJacksonJSON序列化,支持复杂对象主流JSON交互场景
MarshallingMessageConverterJDK序列化二进制格式,高效但跨语言差Java系统内部通信
ContentTypeDelegatingMessageConverter多种根据Content-Type动态选择多协议混合系统
三、配置与使用
1. 基础配置方式
@Configuration
public class RabbitConfig {@Beanpublic MessageConverter jsonMessageConverter() {return new Jackson2JsonMessageConverter();}// 或使用更灵活的内容协商转换器@Bean public MessageConverter contentTypeConverter() {ContentTypeDelegatingMessageConverter converter = new ContentTypeDelegatingMessageConverter();converter.addDelegate("application/json", new Jackson2JsonMessageConverter());converter.addDelegate("text/plain", new SimpleMessageConverter());return converter;}
}
2. 发送复杂对象
@RestController
public class OrderController {@Autowiredprivate RabbitTemplate rabbitTemplate;@PostMapping("/order")public String createOrder(@RequestBody Order order) {// 自动使用配置的Jackson转换器rabbitTemplate.convertAndSend("order.exchange", "order.create", order);return "Order sent";}
}
3. 接收消息处理
@Component
public class OrderListener {// 自动反序列化为Order对象@RabbitListener(queues = "order.queue")public void processOrder(Order order) {System.out.println("Received order: " + order.getId());}// 获取原始Message对象@RabbitListener(queues = "audit.queue")public void auditOrder(Message message) {byte[] body = message.getBody();MessageProperties props = message.getMessageProperties();System.out.println("ContentType: " + props.getContentType());}
}
四、高级定制方案
1. 自定义Jackson配置
@Bean
public Jackson2JsonMessageConverter customJsonConverter() {ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);return new Jackson2JsonMessageConverter(mapper);
}
2. 类型转换增强
public class SmartMessageConverter extends Jackson2JsonMessageConverter {@Overridepublic Object fromMessage(Message message) throws MessageConversionException {MessageProperties props = message.getMessageProperties();if (props.getHeaders().containsKey("__TypeId__")) {props.setHeader(JsonTypeIdResolver.CLASS_NAME_FIELD, props.getHeaders().get("__TypeId__"));}return super.fromMessage(message);}
}
3. 多版本兼容处理
@Bean
public MessageConverter versionedJsonConverter() {Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();converter.setClassMapper(new ClassMapper() {@Overridepublic void fromClass(Class<?> clazz, MessageProperties properties) {properties.setHeader("X-Object-Type", clazz.getName());properties.setHeader("X-Data-Version", "2.1");}@Overridepublic Class<?> toClass(MessageProperties properties) {String version = properties.getHeader("X-Data-Version");return "2.1".equals(version) ? OrderV2.class : Order.class;}});return converter;
}
五、生产环境最佳实践
  1. 强制内容类型声明

    rabbitTemplate.convertAndSend(exchange, routingKey, message, m -> {m.getMessageProperties().setContentType("application/json");return m;
    });
    
  2. 消息大小监控

    @Bean
    public MessageConverter monitoringConverter(MessageConverter delegate) {return new MessageConverter() {@Overridepublic Message toMessage(Object object, MessageProperties messageProperties) {Message msg = delegate.toMessage(object, messageProperties);monitor.messageSize(msg.getBody().length);return msg;}//...其他方法实现};
    }
    
  3. 安全防护建议

    @Bean
    public Jackson2JsonMessageConverter safeJsonConverter() {ObjectMapper mapper = new ObjectMapper();// 防止JSON注入mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);return new Jackson2JsonMessageConverter(mapper);
    }
    
六、常见问题解决方案

问题1:反序列化ClassNotFound

// 解决方案:统一类型映射
@Bean
public Jackson2JsonMessageConverter converter() {Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();converter.setTypePrecedence(TypePrecedence.TYPE_ID);converter.setClassMapper(new DefaultClassMapper() {{setDefaultType(Order.class);setIdClassMapping(Map.of("order", Order.class));}});return converter;
}

问题2:日期格式不兼容

@Bean
public Jackson2JsonMessageConverter dateFormatConverter() {ObjectMapper mapper = new ObjectMapper().setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).registerModule(new JavaTimeModule());return new Jackson2JsonMessageConverter(mapper);
}

问题3:大文件传输优化

// 使用压缩转换器
public class CompressingMessageConverter implements MessageConverter {private final MessageConverter delegate = new SimpleMessageConverter();@Overridepublic Message toMessage(Object object, MessageProperties messageProperties) {byte[] data = (byte[]) delegate.toMessage(object, messageProperties).getBody();return new Message(compress(data), messageProperties);}private byte[] compress(byte[] data) { /* GZIP压缩实现 */ }
}
七、性能对比测试数据
转换器类型1KB对象序列化耗时反序列化耗时消息体积
JDK序列化2ms1ms589B
Jackson(无类型信息)3ms2ms328B
Jackson(含类型信息)4ms3ms412B
Protobuf(需预先编译)1ms0.5ms215B

测试环境:Spring Boot 2.7 + RabbitMQ 3.10,对象包含10个字段

通过合理选择消息转换器,您可以:

  • 实现跨语言系统集成(推荐JSON)
  • 提升Java内部通信效率(二进制协议)
  • 处理特殊数据格式需求(自定义转换器)

相关文章:

202527 | RabbitMQ-基础 | 队列 | Direct + Fanout + Topic 交换机 | 消息转换器

RabbitMQ RabbitMQ 架构与核心概念详解 一、整体架构图 #mermaid-svg-UTlKmvHL7RNWK6vu {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-UTlKmvHL7RNWK6vu .error-icon{fill:#552222;}#mermaid-svg-UTlKmvHL7RNWK6v…...

【学习笔记】服务器上使用 nbconvert 将 Jupyter Notebook 转换为 PDF

1. 环境准备&#xff1a;安装必要工具 在服务器终端运行以下命令&#xff0c;确保依赖已安装&#xff1a; (1) 安装 nbconvert 和 pandoc pip install nbconvert pandoc (2) 安装 LaTeX&#xff08;推荐 TeX Live&#xff09; # Ubuntu/Debian sudo apt-get update sudo a…...

List、Set集合通过Stream流求和

目录 一、泛型为Integer、Long、Double、BigDecimal求和 二、泛型为实体类 对单个属性求和 对多个属性分别分组求和 并返回聚合后的对象 多字段乘积求和&#xff08;基本数据类型&#xff09; 多字段乘积求和&#xff08;BigDecimal&#xff09; 对对象中的多个字段求和…...

微软VSCode 能否击败 Cursor 和 Windsurf?

微软是否能利用平台优势和许可限制来阻止竞争对手? AI 代码编辑器之战加剧 蓬勃发展的 AI 代码编辑领域竞争日益激烈,这个最具变革性和盈利性的新技术领域正在适应相互间的竞争。Visual Studio Code 目前是最主导的代码编辑器。 “根据 Stack Overflow 调查,Visual Studi…...

VSCode会击败Cursor和Windsurf吗?

VSCode 会击败 Cursor 和 Windsurf 吗&#xff1f;微软能不能靠自己的地盘优势和规则限制打压对手&#xff1f;答案是"能"&#xff0c;但他们真的会这么干吗&#xff1f; Cursor & Windsurf vs VSCode Copilot 大PKAI编程工具大战越来越激烈现在最火最赚钱的AI…...

机器学习(4)—— K近邻算法

文章目录 1. K近邻算法&#xff08;K-Nearest Neighbors, KNN&#xff09;原理1.1. K近邻算法是什么算法&#xff1f;1.2. 核心思想 2. K近邻算法的步骤2.1. 选择K值2.2. 计算距离2.3. 选择最近邻&#xff1a;2.4. 做出预测&#xff1a; 3. K值的选择4. 数据标准化5. 优缺点6. …...

深入解读 React 纯组件(PureComponent)

什么是纯组件&#xff1f; React 的纯组件(PureComponent)是 React.Component 的一个变体&#xff0c;它通过浅比较(shallow comparison)props 和 state 来自动实现 shouldComponentUpdate() 方法&#xff0c;从而优化性能。 核心特点 1. 自动浅比较&#xff1a; PureCompon…...

常见MQ及类MQ对比:Redis Stream、Redis Pub/Sub、RocketMQ、Kafka 和 RabbitMQ

常见MQ及类MQ对比 基于Grok调研 Redis Stream、Redis Pub/Sub、RocketMQ、Kafka 和 RabbitMQ 关键点&#xff1a; Redis Pub/Sub 适合简单实时消息&#xff0c;但不持久化&#xff0c;消息可能丢失。Redis Stream 提供持久化&#xff0c;适合需要消息历史的场景&#xff0c;但…...

202528 | RabbitMQ-高级 | 消息可靠性 | 业务幂等性 | 延迟消息

消息可靠性 RabbitMQ发送者可靠性 一、发送者重连机制 #mermaid-svg-gqr6Yr5UNZX87ZDU {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-gqr6Yr5UNZX87ZDU .error-icon{fill:#552222;}#mermaid-svg-gqr6Yr5UNZX87ZD…...

Java EE期末总结(第六章)

一、IoC 1、Bean装配流程 IOC装配流程在代码中的对应就体现在Service这个注解 依赖注入在代码中体现在 &#xff0c;比如 Resource UserService userService 二、AOP 简化流程&#xff0c;为程序员简便操作 tmd编不下去了我自己看视频都没理解md不弄了&#xff1b; 给两个…...

ASP.NET Core 性能优化:内存缓存

文章目录 前言一、什么是缓存二、内存缓存三、使用内存缓存1&#xff09;注册内存缓存服务2&#xff09;注入与基本使用3&#xff09;高级用法GetOrCreate&#xff08;避免缓存穿透&#xff09;异步方法&#xff1a;GetOrCreateAsync&#xff08;避免缓存穿透&#xff09;两种过…...

Go小技巧易错点100例(二十六)

本期分享&#xff1a; 1. string转[]byte是否会发生内存拷贝 2. Go程序获取文件的哈希值 正文&#xff1a; string转[]byte是否会发生内存拷贝 在Go语言中&#xff0c;字符串转换为字节数组&#xff08;[]byte&#xff09;确实会发生内存拷贝。这是因为在Go中&#xff0c;字…...

《算法笔记》3.5小节——入门模拟->进制转换

1022 D进制的AB #include <iostream> using namespace std; int maxn32;int main() {int z[maxn],num0,a,b,d;cin>>a>>b>>d;int resab;do{z[num]res%d;resres/d;}while(res);for (int i num-1; i >0 ; i--) {cout<<z[i];}return 0; }问题 A:…...

【MQTT-协议原理】

MQTT-协议原理 ■ MQTT-协议原理■ MQTT-服务器 称为"消息代理"&#xff08;Broker&#xff09;■ MQTT协议中的订阅、主题、会话■ 一、订阅&#xff08;Subscription&#xff09;■ 二、会话&#xff08;Session&#xff09;■ 三、主题名&#xff08;Topic Name&a…...

JWT认证服务与授权 .netCore

1.实现流程图 2.认证信息概述 Header:System.IdentityModel.Tokens.Jwt.JwtHeader Payload: System.IdentityModel.Tokens.Jwt.JwtPayload Issuer: http://localhost:7200 Audience: http://localhost:7200 Expiration: 2025/4/11 15:06:14 Claim - Type: http://schemas…...

编译原理 实验二 词法分析程序自动生成工具实验

文章目录 实验环境的准备实验实验预备知识分析案例所要做的任务实战 实验环境的准备 安装flex 安装MinGW MinGW Installation Manager页面 apply changes 下载比较耗时 只看到了一个文件&#xff0c;复制过去 配置环境变量 使用gcc -v检验是否安装完成 实验 实验预备知识…...

【C++初学】课后作业汇总复习(一)概述、输入输出、类的入门——理解封装

一、概述、输入输出、类的入门——理解封装 - 1. ab input two number output sum of a and b; #include <iostream>using namespace std;int main() {int a 0;int b 0;cin >> a >> b;cout << ab <<endl;return 0; }2.输入1~7任意一个整数&…...

数学建模:针对汽车行驶工况构建思路的延伸应用

前言&#xff1a; 汽车行驶工况构建的思简单理解为将采集的大量数据进行“去除干扰、数据处理&#xff0c;缩减至1800S的数据”&#xff0c;并可达到等效替换的目的&#xff0c;可以使在试验室快速复现&#xff1b;相应的解决思路、办法可应用在 “通过能量流采集设备大量采集…...

Qt 之opengl shader language

着色器示例代码 实际运行效果...

dolphinscheduler创建文件夹显示存储未启用的问题--已解决

只要修改api-server/comf/common.properties和standalone-server/conf/common.properties里面的内容就可以了&#xff0c;应为你要靠standalone-server这个服务启动dolphinscheduler-web&#xff0c;其他就算怎么改你重启dolphinscheduler的时候系统也不会识别新的common.prope…...

解密 Linux 线程:多线程编程与资源管理

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; 在Linux中&#xff0c;线程 是一种轻量级的执行单元&#xff0c;它是进程的一部分。多个线程可以在同一个进程内并行执行任务&#xff0c;通常它们共享该进程的资源&#xff0c;如内存空间、文件描述符等。…...

Node.js net模块详解

Node.js 的 net 模块提供了基于 TCP 或 IPC 的网络通信能力&#xff0c;用于创建服务器和客户端。以下是 net 模块的核心 API 详解&#xff0c;包含类、方法、事件及示例。 1. 模块引入 const net require(net);2. 核心类与方法 2.1 net.Server 类 用于创建 TCP 或 IPC 服务…...

Node.js中fs模块详解

Node.js 中 fs 模块&#xff08;非 Promise&#xff09;API 详解 Node.js 的 fs 模块提供了同步和异步的文件系统操作。以下是非 Promise 版本的 API 详解&#xff1a; 1. 文件读取操作 const fs require(fs);// 异步读取文件 fs.readFile(file.txt, utf8, (err, data) >…...

Mouse without Borders – 用一套鼠标 / 键盘控制四台电脑

同时操控 2 台电脑&#xff0c;只需一个鼠标和键盘&#xff01;完全免费&#xff0c;由微软官方提供 | 零度解说_哔哩哔哩_bilibili Mouse Without Borders 简介‌ Mouse Without Borders&#xff08;无界鼠标&#xff09;是由微软开发的免费键鼠共享工具&#xff0c;支持在局…...

《车辆人机工程-汽车驾驶操纵实验》

汽车操纵装置有哪几种&#xff0c;各有什么特点 汽车操纵装置是驾驶员直接控制车辆行驶状态的关键部件&#xff0c;主要包括以下几种&#xff0c;其特点如下&#xff1a; 一、方向盘&#xff08;转向操纵装置&#xff09; 作用&#xff1a;控制车辆行驶方向&#xff0c;通过转…...

使用DaemonSet部署集群守护进程集

使用DaemonSet部署集群守护进程集 文章目录 使用DaemonSet部署集群守护进程集[toc]一、使用DaemonSet部署日志收集守护进程集二、管理DaemonSet部署的集群守护进程集1.对DaemonSet执行滚动更新操作2.对DaemonSet执行回滚操作3.删除DaemonSet 一、使用DaemonSet部署日志收集守护…...

破解升腾c10,改造成下载机(第二篇:获取xterm终端)

当c10刷好华为ct3100系统后&#xff0c;就开始获取xterm终端&#xff0c;然后再安装entware. 第一步&#xff1a;获取xterm终端。 点击桌面左下角的工具图标 再点browser 输入百度网址&#xff0c;访问&#xff01; 然后再将网页另存为&#xff5e;&#xff5e;&#xff5e;…...

浏览器多开

使用浏览器的用户功能&#xff0c;创建多个用户即可完成浏览器多开的需求&#xff0c;插件等相对独立 需要命名 然后就可以通过多个用户切换来实现多开了&#xff0c;不同任务选择不同用户...

使用Python实现的音符生成和节拍器程序

推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 **摘要****先决条件****设置**生成音符频率播放音符节拍器合并结论摘要 节拍器和随机音符生成器各有用途,但单独使用时功能有限。本…...

【生活相关-日语-日本-东京-留学生-搬家后或新入驻-水道局申请饮用水(1)-办理手续】

【生活相关-日语-日本-东京-搬家后-水道局申请饮用水-办理手续】 1、前言2、情况说明&#xff08;1&#xff09;他人代办&#xff08;2&#xff09;打电话&#xff08;3&#xff09;网络申请&#xff08;4&#xff09;你将会面临什么&#xff0c;主要步骤&#xff08;5&#xf…...

PyTorch模型构造实战:从基础到复杂组合

本文通过多个示例演示如何使用PyTorch构建不同类型的神经网络模型&#xff0c;涵盖基础多层感知机、自定义块、顺序块以及复杂组合模型。所有代码均附带输出结果&#xff0c;帮助读者直观理解模型结构。 1. 多层感知机&#xff08;MLP&#xff09; 使用nn.Sequential快速构建一…...

【高性能缓存Redis_中间件】一、快速上手redis缓存中间件

一、铺垫 在当今的软件开发领域&#xff0c;消息队列扮演着至关重要的角色。它能够帮助我们实现系统的异步处理、流量削峰以及系统解耦等功能&#xff0c;从而提升系统的性能和可维护性。Redis 作为一款高性能的键值对数据库&#xff0c;不仅提供了丰富的数据结构&#xff0c;…...

并发编程--互斥锁与读写锁

并发编程–互斥锁与读写锁 文章目录 并发编程--互斥锁与读写锁1. 基本概念2. 互斥锁2.1 基本逻辑2.2 函数接口2.3示例代码12.4示例代码2 3. 读写锁3.1 基本逻辑3.2示例代码 1. 基本概念 互斥与同步是最基本的逻辑概念&#xff1a; 互斥指的是控制两个进度使之互相排斥&#x…...

Linux下Docker安装超详细教程(以CentOS为例)

前言 Docker 已成为现代应用开发和部署的标配工具。本教程将手把手教你 在 CentOS 系统上安装 Docker&#xff0c;涵盖从环境准备到验证安装的全流程&#xff0c;并解决常见问题。无论你是运维工程师还是开发者&#xff0c;均可快速上手。 一、环境要求 操作系统 CentOS 7 或更…...

Ubuntu 服务器版本 设置socket服务(Python)

1. 确定 Socket 类型 Socket 服务可以是: 网络 Socket:基于 TCP/UDP 协议(如 Web 服务器、API 服务)。 Unix Domain Socket:本地进程间通信(如 Docker、MySQL 默认使用)。 2. 编写一个简单的 Socket 服务示例(Python) 以 Python 为例,创建一个 TCP Socket 服务:…...

对于GAI虚假信息对舆论观察分析

摘要 生成式人工智能&#xff08;Generative Artificial Intelligence, GAI&#xff09;的技术革新重构了信息生产机制&#xff0c;但也加剧了虚假信息对舆论生态的异化风险。 关键词&#xff1a;生成式人工智能、虚假信息、舆论异化、智能治理 一、生成式人工智能虚假信息下…...

HTTP:三.HTTP连接

HTTP(Hypertext Transfer Protocol)是一种用于传输超文本数据的应用层协议。它是互联网上最常用的协议,用于在客户端和服务器之间传输数据。HTTP协议通常用于从Web服务器传输网页和文件到客户端浏览器,并支持其他用途,如传输API数据和传输文件。 HTTP连接是指客户端向服务…...

hyper-v server服务器部署远程访问(我目前环境:hyper-v服务器+路由器+公网ip)

Hyper-v server部署(裸金属方式) 系统镜像下载安装# 下载地址:17763.737.190906-2324.rs5_release_svc_refresh_SERVERHYPERCORE_OEM_x64FRE_zh-cn_1.iso 安装的过程很简单,和安装Windows操作系统没啥区别,这里就不记录了。 安装过程可参考:安装Hyper-v Server 2016 部…...

MCP遇见Web3:从边缘计算到去中心化的无限想象

MCP遇见Web3:从边缘计算到去中心化的无限想象 在数字化转型的浪潮中,边缘计算(MCP,Micro Control Protocol)和Web3技术分别在计算效率与去中心化架构上发挥着各自的优势。当两者融合,会碰撞出哪些火花?作为一名技术极客,我最近开始深度研究MCP与Web3工具的集成,试图探…...

【HarmonyOS Next之旅】DevEco Studio使用指南(十三) -> ArkTS/TS代码重构

目录 1 -> Refactor-Extract代码提取 2 -> Refactor-Convert代码转换 3 -> Refactor-Rename代码重命名 4 -> Move File 5 -> Safe Delete 1 -> Refactor-Extract代码提取 在编辑器中支持将函数内、类方法内等区域代码块或表达式&#xff0c;提取为新方…...

STM32 HAL DHT11驱动程序

DHT11驱动程序会占用TIM3定时器&#xff0c;进行高精度延时。程序共包含4个文件 DHT11.c DHT11.h delay.c delay.h DHT11.c #include "stm32f1xx_hal.h" #include "dht11.h" #include "delay.h" // 添加延时头文件 #define DHT_PORT GPIOB…...

asm汇编源代码之文件操作相关

提供7个子程序:   1. 关闭文件 FCLOSE   2. 打开文件 FOPEN   3. 文件大小 FSIZE   4. 读文件 FREAD   5. 写文件 FWRITE   6. 建立文件 FCREATE   7. 读取或设置文件指针 FPOS 具体功能及参数描述如下 ; ---------------------------- FCLOSE PROC  FAR ; IN…...

Github 2025-04-12 Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-04-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10TypeScript项目2uv: 极快的Python软件包安装程序和解析器 创建周期:147 天开发语言:Rust协议类型:Apache License 2.0Star数量:7…...

JAVA学习-练习试用Java实现“实现一个Java程序,对大数据集中的数据进行类型转换”

问题&#xff1a; 实现一个Java程序&#xff0c;对大数据集中的数据进行类型转换。 解答思路&#xff1a; 在Java中&#xff0c;对大数据集中的数据进行类型转换通常意味着将一种数据类型转换为另一种数据类型。以下是一个简单的Java程序示例&#xff0c;它演示了如何对大数据集…...

Android基础彻底解析-APK入口点,xml,组件,脱壳,逆向

第一章:引言与背景 Android逆向工程,作为一种深入分析Android应用程序的技术,主要目的就是通过分析应用的代码、资源和行为来理解其功能、结构和潜在的安全问题。它不仅仅是对应用进行破解或修改,更重要的是帮助开发者、研究人员和安全人员发现并解决安全隐患。 本文主要对…...

Spark RDD算子详解:从入门到精通

一、前言 在大数据处理领域&#xff0c;Apache Spark凭借其高效的内存计算能力&#xff0c;成为了流行的分布式计算框架。RDD&#xff08;Resilient Distributed Dataset&#xff09;是Spark的核心概念之一&#xff0c;它是一个分布式的数据集合&#xff0c;提供了丰富的操作接…...

Bootstrap4 卡片

Bootstrap4 卡片 Bootstrap 是一个流行的前端框架&#xff0c;它提供了丰富的组件和工具&#xff0c;使得开发者可以快速构建响应式、美观的网页。其中&#xff0c;Bootstrap4 中的卡片组件&#xff08;Card&#xff09;是一个非常实用的功能&#xff0c;可以用来展示图片、文…...

【随行付-注册安全分析报告-无验证方式导致隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…...

深入解析Antogen意图识别模型:从原理到实践

一、意图识别基础概念 1.1 什么是意图识别 意图识别(Intent Recognition)是自然语言处理(NLP)中的核心任务&#xff0c;旨在确定用户输入背后想要表达的目的或行动请求。它是对话系统理解用户的第一步&#xff0c;直接影响后续的对话管理和响应生成质量。 关键特征&#xff…...

企业年报问答RAG挑战赛冠军方案:从零到SotA,一战封神

RAG挑战赛是什么&#xff1f; 任务是基于企业年报构建问答系统。比赛日的流程简而言之&#xff1a; 解析阶段&#xff1a;获得100份随机企业的年报&#xff08;PDF格式&#xff0c;每份最多1000页&#xff09;&#xff0c;限时2.5小时完成解析并构建数据库。问答阶段&#xf…...