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

苍穹外卖优化-续

1、spring中的redis配置

模块关键配置/注解作用一句话必须/可选快速记忆口诀
Redis 序列化ObjectMapper.setVisibility(ALL,ANY)让 Jackson 读到 private 字段,否则只能读public字段必须无它 → 空 JSON{}

objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

registerModule(JavaTimeModule)

LocalDateTime 不报错、不转时间戳必须无它 → 时间乱码
activateDefaultTyping(...)支持“父类变量存子类对象”可选用不到就注释
RedisTemplate<String, Object> 用法,value用的JSON的序列化器redisTemplate.opsForValue().set(key,obj,ttl)手动存任意 Java 对象,自动转为JSON格式的——复杂/定时缓存用它
redisTemplate.opsForValue().get(key)手动读对象,读出来是Object类型,强转指定类型即可——序列化器已帮你转好
Spring Cache 开关@EnableCaching 打在启动类让 @Cacheable 生效必须漏加 → 注解全失效
CacheManager 配置,SpringCache的核心接口GenericJackson2JsonRedisSerializer注解缓存以 JSON 存 Redis必须无它 → 二进制乱码
.entryTtl(Duration.ofMinutes(30))默认 30 min 过期推荐

防数据永驻

SpringCache 注解放置层仅 Service 层Controller/Mapper 都不放铁律放错 → 重复缓存 or 缓存失效
查询缓存@Cacheable(value="biz:func",key="#p0+'-'+#p1")有缓存直接返回常用value 即前缀,key 拼参数
修改清缓存@CacheEvict(value="biz:func",allEntries=true)改库后整组清常用只改一条时改 key 精准清除
缓存键命名规则业务:功能:唯一标识 例:dish:id:1全局不冲突、可排查推荐冒号分层,IDE 全局搜
redis写入基础类型,value是JSON序列化器直接 set(key,Integer)Jackson 会转 JSON 值 "1"——看起来没转,实际已转
redis写入复杂对象,value是JSON序列化器直接 set(key,DishVO)Jackson 转完整 JSON——可读、可调试
序列化器对比RedisTemplate vs. CacheManager手动 API vs. 注解根据应用场景选择

2、常见缓存问题及其解决方案

问题典型场景解决方案方法逻辑(一句话)具体实现要点(直接抄代码)Redis 里真实形态坑点提示
缓存穿透数据库&缓存都无数据,每次打DB空值占位把 "" 写回 Redis,TTL 短if(db==null) redis.set(key,"",2min)""别忘了给空值加过期时间,否则永远进不来
缓存击穿热点 key 瞬时过期,高并发全部打到 DB① 互斥锁① 只让 1 个线程重建① setnx 抢锁 → 查 DB → 写缓存 → del 锁① 正常 JSON① 锁一定加过期时间防止死锁
缓存雪崩大量 key 同时失效,请求雪崩随机 TTL + 集群 + 限流 + 多级缓存让过期时间 分散TTL = base + Random(0~300)s正常 JSON随机值范围别太小,否则仍可能批量失效

缓存穿透:  查询→DB无→Redis写""→下次直接返回空
缓存击穿:  查询→Redis无/过期→抢锁→只有1线程重建→其余线程短暂等待 or 先返回旧数据
缓存雪崩:  批量查询→Redis同时过期→随机TTL打散→数据库负载平滑

建议封装成Redis的工具类,传参调用相应的功能类中的方法:

3、RabbitMQ使用前的配置

模块关键要点配置/代码片段备注
1. 依赖必引包spring-boot-starter-amqp后者支持 LocalDateTime
2. 连接yml 最简配置host/port/username/password/virtual-host生产环境换账号
3. 队列/交换机配置类一次性声明@Bean public Queue + DirectExchange + Bindingdurable=true 持久化
4. 生产者发消息入口rabbitTemplate.convertAndSend(exchange, routingKey, dto)dto 为 POJO
5. 消费者监听入口@RabbitListener(queues = "xxx")方法参数直接写 dto 类型
6. 序列化必换 JSON自定义 RabbitTemplate 并 setMessageConverter(new Jackson2JsonMessageConverter(objectMapper))解决可读性/兼容性/安全
7. 对象兼容性字段一致即可无需 Serializable但建议加上防意外
8. 持久化三件套队列+交换机+消息创建时 durable=true重启不丢
9. 生产者确认确保“发到 Rabbit”yml: publisher-confirm-type: correlated失败记录日志/重发
10. 消费者确认确保“处理完”yml: acknowledge-mode: manual异常 basicNack(tag, false, false) 进死信
11. 死信队列失败消息兜底普通队列加 x-dead-letter-exchange 等参数人工后续处理
12. 常见消息类型字符串/基本类型/POJO/List/Map统一走 JSON 转换器控制台可直接查看 JSON

4、消费者类加 @Component 注解的原因

心作用具体说明不添加的后果
让 Spring 识别并管理 Bean@Component 是 Spring 基础组件注解,标记后 Spring 会扫描并将消费者纳入容器管理,成为 Spring Bean。消费者类不被 Spring 管理,@RabbitListener 注解无法被 Spring 的 RabbitMQ 监听容器解析,监听逻辑失效。
支持依赖注入消费者通常依赖其他 Spring Bean(如SmsServiceStockMapper),只有自身是 Spring Bean,才能通过@Autowired注入依赖。无法注入依赖,业务逻辑(如发送短信、扣减库存)无法执行,抛出NullPointerException

5、DirectRabbitConfig 配置类工作机制,能生效的原因

第一步:Spring 启动时,自动创建核心组件

Spring 启动时会扫描 @Configuration 标记的 DirectRabbitConfig 类,执行其中所有 @Bean 注解的方法,将返回的「队列」「交换机」「绑定关系」注册到 RabbitMQ 服务器:

配置模块核心职责工作流程(启动时 + 运行时)关键规则(直连交换机)
队列(Queue)定义消息的「存储容器」,设置是否持久化、排他、自动删除等属性(如TestDirectQueue)。启动时:Spring 调用 RabbitMQ API,在服务器创建指定队列;运行时:接收交换机转发的消息,供消费者获取。持久化(durable=true)确保 RabbitMQ 重启后队列不丢失。
交换机(DirectExchange)定义消息的「路由中转站」(如TestDirectExchange),接收生产者发送的消息。启动时:Spring 在 RabbitMQ 创建直连交换机;运行时:接收消息,根据路由键匹配绑定关系。直连交换机仅转发「路由键完全匹配」的消息。
绑定(Binding)关联「交换机 - 队列 - 路由键」(如TestDirectRouting),定义消息转发规则。启动时:Spring 在 RabbitMQ 建立绑定关系;运行时:交换机通过绑定关系找到目标队列,完成消息转发。路由键是绑定的核心,生产者需指定相同路由键才能匹配。
整体转发逻辑串联「生产者 - 交换机 - 队列 - 消费者」,实现消息路由。1. 生产者发送消息(指定交换机 + 路由键)→ 2. 交换机匹配绑定关系 → 3. 消息转发到目标队列 → 4. 消费者监听队列获取消息。路由键不匹配时,消息会丢失(需配置死信交换机避免)。

6、自定义rabbitTemplate属性, 类型的自动转换,以及和生产者/消费者 的 写入/读取 时出现的问题

模块关键点具体做法备注
异常摘要Cannot convert from byte[] to com.sky.entity.OrderPOSpring 缺省转换器无法把字节流变实体;
我的问题是,rabbitTemplate配置了自定义的序列化器(JSON格式的),即生产者写入的时候value是JSON格式的,但是消费者读取的时候没有设置序列化器,导致字节流无法转换为我的实体类
死信队列二次失败同理
根因消息转换器未配置或两端不一致生产者/消费者至少一方无 JSON 转换器消息头 contentType 虽对,但体不是合法 JSON
步骤1:消费者配置声明 Jackson2JsonMessageConverter给 SimpleRabbitListenerContainerFactory 设 setMessageConverter(new Jackson2JsonMessageConverter())

或者直接(见下图)
@RabbitListener(queues = RabbitConstant.QUEUE_ORDER_DEAD,messageConverter = "jackson2JsonMessageConverter")
这个jackson2JsonMessageConverter需要自己注入,变成Bean
配置类加 @Configuration
步骤2:生产者配置声明 Jackson2JsonMessageConverter给 RabbitTemplate 设 setMessageConverter(new Jackson2JsonMessageConverter())发送时直接 convertAndSend(exchange, routingKey, orderPO)
步骤3:实体类校验可反序列化

① @NoArgsConstructor 必备

实体类的可反序列化性:必须有默认无参构造函数、字段类型匹配、避免循环依赖(OrderPO 中若有其他实体引用(如 UserPO),需确保无循环依赖,或用 @JsonIgnore 排除不需要序列化的字段。)

Lombok 组合:@Data+@Builder+@AllArgsConstructor+@NoArgsConstructor
验证流程清消息 → 重启 → 观察控制台① purge 原队列与死信队列
无历史脏数据,快速验证

http://www.xdnf.cn/news/20495.html

相关文章:

  • Java包装类型
  • Git 长命令变短:一键设置别名
  • Linux以太网模块
  • 【嵌入式】【科普】AUTOSAR学习路径
  • 《无畏契约》游戏报错“缺少DirectX”?5种解决方案(附DirectX修复工具)
  • 基于单片机智能行李箱设计
  • 云手机运行流畅,秒开不卡顿
  • 无拥塞网络的辩证
  • 24.线程概念和控制(一)
  • 贪心算法应用:数字孪生同步问题详解
  • B.50.10.10-微服务与电商应用
  • 关于退耦电容
  • 【LeetCode热题100道笔记】将有序数组转换为二叉搜索树
  • 3分钟快速入门WebSocket
  • Scikit-learn Python机器学习 - 特征降维 压缩数据 - 特征提取 - 主成分分析 (PCA)
  • dify+Qwen2.5-vl+deepseek打造属于自己的作业帮
  • 第27节:3D数据可视化与大规模地形渲染
  • 如何下载小红书视频
  • MySQL的组复制(MGR)高可用集群搭建
  • vue3图标终极方案【npm包推荐】vue3-icon-sui(含源码详解)
  • STM32F4芯片RS485使用记录
  • 小迪自用web笔记29
  • 少儿配音教育:广州声与色在线科技有限公司打造趣味课程,助力青少年语言能力提升
  • 电脑外接显示屏字体和图标过大
  • 实体商业创新观察:AI 驱动的本地生活服务新模式解析
  • 计算机网络:物理层---物理层的基本概念
  • OpenSSL 1.0.1e 下载解压和运行方法(小白适用 附安装包)​
  • Nginx性能调优:参数详解与压测对比
  • 小孔成像原理
  • 吴恩达机器学习(九)