爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      SpringBoot RabbitMQ 商品秒杀【SpringBoot系列15】

      首页 知识中心 软件开发 文章详情页

      SpringBoot RabbitMQ 商品秒杀【SpringBoot系列15】

      2024-09-25 10:14:09 阅读次数:469

      rabbitmq,springboot

       

      1 项目准备

      本文章是系列文章 ,每节文章都有对应的代码,每节的源码都是在上一节的基础上配置而来,对应的视频讲解课程正在火速录制中。

      如下图所示是本项目实现的一个秒杀下单流程的主要过程:
      SpringBoot RabbitMQ 商品秒杀【SpringBoot系列15】

      2 限流

      本项目限流限制的是每个用户5秒内访问2次获取秒杀地址的接口

      @Api(tags="商品秒杀模块")
      @RestController()
      @RequestMapping("/seckill")
      @Slf4j
      public class SecKillController {
          /**
           * 获取秒杀地址
           */
          // 接口限流
          @AccessLimit(second = 5, maxCount = 2)
          @GetMapping("/path/{id}")
          public R getPath(@PathVariable("id") Long goodsId, @RequestHeader Long userId) {
              // 创建秒杀地址
              return secKillService.createPath(userId, goodsId);
          }
      }
      
      2.1 限流自定义注解 AccessLimit
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.METHOD)
      public @interface AccessLimit {
      
          int second();
      
          int maxCount();
      
          boolean needLogin() default true;
      
      }
      
      

      @Retention修饰注解,用来表示注解的生命周期,生命周期的长短取决于@Retention的属性RetentionPolicy指定的值

      • RetentionPolicy.SOURCE 表示注解只保留在源文件,当java文件编译成class文件,就会消失 源文件 只是做一些检查性的操作,

      • RetentionPolicy.CLASS 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期 class文件(默认) 要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife)

      • RetentionPolicy.RUNTIME 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 运行时也存在 需要在运行时去动态获取注解信息

      @Target 说明了Annotation所修饰的对象范围

      • 1.CONSTRUCTOR:用于描述构造器
      • 2.FIELD:用于描述域
      • 3.LOCAL_VARIABLE:用于描述局部变量
      • 4.METHOD:用于描述方法
      • 5.PACKAGE:用于描述包
      • 6.PARAMETER:用于描述参数
      • 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
      2.2 自定义拦截器 处理限流
      @Component
      @Slf4j
      public class AccessLimitInterceptor implements HandlerInterceptor {
      
          @Autowired
          RedisTemplate redisTemplate;
      
          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
              log.info("==============================AccessLimitInterceptor拦截器==============================");
              if (handler instanceof HandlerMethod) {
                  HandlerMethod hm = (HandlerMethod) handler;
                  AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
                  if (Objects.isNull(accessLimit)) {
                      return true;
                  }
                  int second = accessLimit.second();
                  int maxCount = accessLimit.maxCount();
                  boolean needLogin = accessLimit.needLogin();
                  String uri = request.getRequestURI();
                  if (needLogin) {
                      //需要登录  本项目使用的是 Spring Security 实现安全认证 
                      //认证通过后 才会走到这里 
                      String userId = request.getHeader("userId");
      //                UserInfo userInfo = getUserInfoFromRequest(request);
      //                if (Objects.isNull(userInfo)) {
      //                    toRender(response, "请登录");
      //                    return false;
      //                }
                      uri = uri + ":" + userId;
                  }
                  return toLimit(response, second, maxCount, uri);
              }
              return true;
          }
      
          // 简单计数器限流
          private boolean toLimit(HttpServletResponse response, int second, int maxCount, String uri) throws IOException {
              ValueOperations valueOperations = redisTemplate.opsForValue();
              Integer count = (Integer) valueOperations.get(uri);
              if (Objects.isNull(count)) {
                  valueOperations.set(uri, 1, second, TimeUnit.SECONDS);
              } else if (count < maxCount) {
                  // 计数器加一
                  valueOperations.increment(uri);
              } else {
                  log.info("触发限流规则 限流{}秒访问{}次,当前访问{} {}次 ",second,maxCount,count,uri);
                  // 超出访问限制
                  toRender(response, "当前下单人数排队中 请稍后重试");
                  return false;
              }
              return true;
          }
      
      

      3 发起秒杀

      用户获取到秒杀地址后,使用秒杀地址发起秒杀

          /**
           * 开始秒杀
           * @param goodsId
           * @param userId
           * @return
           */
          @GetMapping("/{path}/toSecKill/{id}")
          public R toSecKill(@PathVariable("id") Long goodsId,
                             @PathVariable String path,
                             @RequestHeader Long userId) {
              // 验证路径是否合法
              boolean isLegal = secKillService.checkPath(path, userId, goodsId);
              if (!isLegal) {
                  return R.error("路径不合法");
              }
              return secKillService.isToSecKill(goodsId, userId);
          }
      

      首先是校验了一下地址的合法,与上述生成地址的规则一致,然后就是预下单生成订单号的过程:

      @Service("secKillService")
      @Slf4j
      public class SecKillServiceImpl implements SecKillService, InitializingBean {
          @Autowired
          private RedisTemplate redisTemplate;
      
          @Autowired
          private SecKillGoodsService secKillGoodsService;
      
          @Autowired
          private SecKillOrderService secKillOrderService;
      
          @Autowired
          private OrderMQSender mqSender;
          // 空库存的 map 集合
          private Map<Long, Boolean> emptyStockMap = new HashMap<>();
          @Autowired
          SnowFlakeCompone snowFlakeCompone;
          @Override
          public R isToSecKill(Long goodsId, Long userId) {
      
              // 重复抢购
              SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("order:" + userId + ":" + goodsId);
              if (!Objects.isNull(seckillOrder)) {
                  return R.error("重复抢购");
              }
              // 内存标记,减少 Redis 的访问
              if (emptyStockMap.get(goodsId)) {
                  // 库存为空
                  return R.error("商品库存不足");
              }
              //库存 key
              String redisStockKey = "seckillGoods:" + goodsId;
      
              Boolean aBoolean = redisTemplate.hasKey(redisStockKey);
              if(Boolean.FALSE.equals(aBoolean)){
                  emptyStockMap.put(goodsId, true);
                  return R.error("商品库存不足");
              }
      
              ValueOperations valueOperations = redisTemplate.opsForValue();
      
              // 预减库存
              Long stock = valueOperations.decrement(redisStockKey);
              // 库存不足
              if (stock < 0) {
                  emptyStockMap.put(goodsId, true);
                  valueOperations.increment(redisStockKey);
                  return R.error("商品库存不足");
              }
              //生成订单号
              long sn = snowFlakeCompone.getInstance().nextId();
              //保存到redis中 状态 doing 正在处理中
              redisTemplate.opsForValue().set("sn:"+sn, "doing");
              // 秒杀消息
              SecKillMessage message = new SecKillMessage(userId, goodsId,sn);
              mqSender.sendSecKillMessage(JsonUtils.toJson(message));
              //把订单号返回给前端
              return R.okData(sn);
          }
      
      

      内存中保存的库存信息与Redis中保存的库存信息,是通过定时任务在开始秒杀的前一小时同步进来的,定时任务会在后续的篇章里集成。

      订单号返回前端,前端就开始轮循查询订单状态的接口

          /**
           * 查询订单状态与详情
           * 商品-下单入口调用
           * @param sn
           * @return
           */
          @GetMapping("/statues/detail/{sn}")
          public R detailAndStatue(@PathVariable("sn") Long sn) {
              //redis 中查询状态
              Boolean aBoolean = redisTemplate.hasKey("sn:" + sn);
              if(Boolean.FALSE.equals(aBoolean)){
                  return R.error("下单失败");
              }
              String snStatues = redisTemplate.opsForValue().get("sn:" +sn).toString();
              //未下单完
              if(snStatues.equals("doing")){
                  return R.error(202,"处理中");
              }
              //未下单成功
              if(!snStatues.equals("ok")){
                  return R.error(203,snStatues);
              }
              //下单成功 返回订单信息
              OrderVo orderVo = orderService.detailFromSn(sn);
              return R.okData(orderVo);
          }
      

      前端查询到下单成功后,加载显示订单详情,发起支付。

      4 消息队列

      消息队列、交换机的定义如下:

      @Configuration
      public class OrderRabbitMQTopicConfig {
      
          private static final String QUEUE = "seckillQueue";
          private static final String EXCHANGE = "seckillExchange";
      
      
          @Bean
          public Queue seckillQueue() {
              return new Queue(QUEUE);
          }
      
          @Bean
          public TopicExchange seckillExchange() {
              return new TopicExchange(EXCHANGE);
          }
      
      
          @Bean
          public Binding binding() {
              return BindingBuilder
                      .bind(seckillQueue())
                      .to(seckillExchange()).with("seckill.#");
          }
      }
      

      秒杀预下单消息发送者

      @Service
      @Slf4j
      public class OrderMQSender {
      
      
          @Autowired
          private RabbitTemplate rabbitTemplate;
          /**
           * 秒杀订单走的消息队列
           * @param msg
           */
      
          public void sendSecKillMessage(String msg) {
              log.info("发送消息:{}", msg);
              //参数一 交换机名称 
              //参数二 路由名称
              rabbitTemplate.convertAndSend("seckillExchange", "seckill.message", msg);
          }
       }
      

      秒杀订单 消息接收者 ,对订单的库存进行了二次校验

      @Service
      @Slf4j
      public class OrderMQReceiver {
      
          @Autowired
          private SecKillGoodsService secKillGoodsService;
      
          @Autowired
          private RedisTemplate redisTemplate;
      
          @Autowired
          private OrderService orderService;
      
          @RabbitListener(queues = "seckillQueue")
          public void receiveSecKillMessage(String message) {
              log.info("接收的秒杀订单消息:{}", message);
              SecKillMessage secKillMessage = JsonUtils.toObj(message, SecKillMessage.class);
      
              Long userId = secKillMessage.getUserId();
              Long goodsId = secKillMessage.getGoodsId();
              Long sn = secKillMessage.getSn();
              //查询秒杀商品
              SeckillGoods seckillGoods = secKillGoodsService.findByGoodsId(goodsId);
              // 库存不足
              if (seckillGoods.getStockCount() < 1) {
                  //更新redis订单状态
                  redisTemplate.opsForValue().set("sn:" + sn, "秒杀失败 库存不足",1, TimeUnit.DAYS);
                  log.error("库存不足");
                  return;
              }
      
              // 判断是否重复抢购
              // 重复抢购
              SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("order:" + userId + ":" + goodsId);
              if (!Objects.isNull(seckillOrder)) {
                  //更新redis订单状态
                  redisTemplate.opsForValue().set("sn:" + sn, "秒杀失败 重复抢购",1, TimeUnit.DAYS);
                  log.error("重复抢购 userId:{} goodsId:{}",userId,goodsId);
                  return;
              }
      
              // 下订单
              orderService.toSecKill(goodsId, userId,sn);
          }
      
      }
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://biglead.blog.csdn.net/article/details/129624311,作者:早起的年轻人,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:Linux:ansible-playbook配置文件(剧本)(进阶)

      下一篇:使用java底层实现邮件的发送(含测试,源码)

      相关文章

      2025-05-12 10:19:12

      SpringBoot学习(6)(Bean对象扫描)(@ComponentScan)

      SpringBoot学习(6)(Bean对象扫描)(@ComponentScan)

      2025-05-12 10:19:12
      Bean , springboot , 启动 , 扫描 , 注解
      2025-05-12 10:19:12

      springboot学习(2)

      springboot学习(2)

      2025-05-12 10:19:12
      Java , main , springboot , web , 启动 , 方法 , 浏览器
      2025-05-08 09:03:21

      springboot酒店管理系统分前后端【源码+数据库】

      本项目是一套springboot酒店管理系统分前后端【源码+数据库】,主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。

      2025-05-08 09:03:21
      springboot , 数据库 , 源码 , 管理 , 项目
      2025-05-07 09:09:26

      springboot系列教程(二十五):springboot整合ElasticSearch,实现高性能搜索引擎

      ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。

      2025-05-07 09:09:26
      ElasticSearch , springboot , 接口 , 搜索引擎
      2025-05-07 09:08:08

      基于springboot框架个人博客管理系统

      本项目是一套基于springboot框架实现的个人博客管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。

      2025-05-07 09:08:08
      springboot , 文章 , 源码 , 页面 , 项目
      2025-05-07 09:07:56

      springboot基于ssm框架实现的家具商城管理系统

      本项目是一套基于springboot框架实现的家具商城管理系统,主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。

      2025-05-07 09:07:56
      springboot , 数据库 , 模块 , 项目
      2025-05-06 09:18:49

      springboot校园宿舍管理系统前后端分离

      springboot校园宿舍管理系统前后端分离

      2025-05-06 09:18:49
      springboot , 数据库 , 源码 , 管理 , 项目
      2025-04-23 08:18:27

      nginx结合前后端分离项目springboot+vue的配置

      项目采用的是前后端分离springboot+vue,通过nginx监听,转发到对应的前端页面或者后台接口调用

      2025-04-23 08:18:27
      nginx , springboot , vue , 分离 , 配置
      2025-04-23 08:18:21

      springboot整合LDAP的另外一种方式并实现增删改查功能

      springboot整合LDAP的另外一种方式并实现增删改查功能

      2025-04-23 08:18:21
      springboot , yml , 改查 , 配置
      2025-04-23 08:18:21

      springboot 整合 LDAP

      springboot 整合 LDAP

      2025-04-23 08:18:21
      LDAP , springboot , 配置
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5265653

      查看更多

      最新文章

      springboot学习(2)

      2025-05-12 10:19:12

      SpringBoot学习(6)(Bean对象扫描)(@ComponentScan)

      2025-05-12 10:19:12

      springboot酒店管理系统分前后端【源码+数据库】

      2025-05-08 09:03:21

      springboot系列教程(二十五):springboot整合ElasticSearch,实现高性能搜索引擎

      2025-05-07 09:09:26

      springboot校园宿舍管理系统前后端分离

      2025-05-06 09:18:49

      Springboot的常见面试题

      2024-12-13 06:56:34

      查看更多

      热门文章

      SpringBoot配置文件分类

      2023-07-27 06:49:01

      springboot接受post/get参数值的几种形式,Java

      2023-04-11 10:14:19

      SpringBoot写的后端API接口如何写得更优雅

      2023-06-15 06:37:47

      Spring Boot 使用拦截器

      2023-05-04 09:43:47

      13_Spring Boot 使用Filter(了解)

      2024-09-24 06:29:51

      Springboot 手动获取bean/getBean的工具类SpringUtil(主要用来获取prototype类型的组件)

      2023-06-13 08:29:06

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      SpringBoot AES加密 PKCS7Padding 模式

      使用fast测试的错误

      SpringBoot 配置 mapper.xml 文件指定

      springboot test 报错解决办法:Unable to find a @SpringBootConfiguration, you need to use @Context

      spring boot中使用generator插件自动生成代码

      MyBatisPlus分页插件在SpringBoot中的使用

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号