33.2从零开始学springboot-一文读懂消息队列-生产消费(附redis实现)

鲜牛奶系统实战:SpringBoot+Vue生鲜订单闭环设计 生鲜电商系统与通用电商存在本质差异,核心在于‘时效性-损耗性-地域性’铁三角约束。本文围绕鲜牛奶这一典型短保品类,解析其业务建模原理:如何通过三维库存(仓配单元+时间窗+状态)保障72小时保质期履约,借助Redis+Lua实现毫秒级库存强一致扣减,并以SpringBoot分布式事务与Vue Composition API协同应对自动续订、冷链调度、支付幂等性等真实场景技术挑战。内容覆盖从领域驱动分层设计、前后端分离部署适配(Windows Server/IIS与Linux/Nginx双环境),到源码可维护性 阅读详情

前言

上一节我们使用Redis实现了发布订阅者模式,关于Redis实现的发布订阅模式的特点,我们也了解了

  • 基于Redis服务主动推送消息,而非订阅者循环拉取.
  • 消息即发即丢(就是消息一发布,就丢失了,不会保存)

那么,实际场景时,我们也会遇到如下的业务场景:

  • 需要保存消息,按需取出
  • 需要异步延迟处理消息,比如预定订单会先入消息队列,而后统一在一个时间集中处理

此时,发布订阅模式就不太适用了
而生产消费模式便能满足这样的需求

生产消费者模式的特点如下:

  • 只有一个消费者将获得消息
  • 生产者不需要在接收者消费该消息期间处于运行状态,接收者也同样不需要在消息发送时处于运行状态。
  • 每一个成功处理的消息都由接收者签收

本节,我们就适用Redis实现生产消费模式

Redis实现生产这消费者模式

Redis,对于队列模型,我们可以使用list数据结构,通过LPUSH和RPOP来实现一个队列.

Springboot+Redis实现

  • 引入redis依赖
    pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • application.yml
spring:
  redis:
    port: 6379
    database: 0
    host: 127.0.0.1
    password: 123456
    jedis:
      pool:
        max-active: 8
        max-wait: -1ms
        max-idle: 8
        min-idle: 0
    timeout: 5000ms
server:
  port: 9999
  • redis配置类
package com.mrcoder.sbredisproducerconsumer.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @Description: Redis配置类
 */
@Configuration
@ConditionalOnClass({RedisTemplate.class})
public class RedisConfig {

    /**
     * Redis操作模板配置
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory connectionFactory, Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer) {
        RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
        template.setConnectionFactory(connectionFactory);
        // 设置key/hashkey序列化
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);

        // 设置值序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();

        template.setKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();

        return template;
    }

    /**
     * 序列化定制
     *
     * @return
     */
    @Bean
    public Jackson2JsonRedisSerializer<Object> jackson2JsonSerializer() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
                Object.class);

        // 初始化objectmapper
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(mapper);
        return jackson2JsonRedisSerializer;
    }


}

  • 定义生产者
package com.mrcoder.sbredisproducerconsumer.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class ProducerService {
    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Scheduled(initialDelay = 5000, fixedDelay = 30 * 1000)
    public void producer() {
        String message = "消息 " + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        System.out.println("-----------生产者------------>生产了:" + message);
        redisTemplate.opsForList().leftPush("queue", message);
    }
}

  • 定义消费者
package com.mrcoder.sbredisproducerconsumer.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class ConsumerService {
    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Scheduled(initialDelay = 5000, fixedDelay = 60 * 1000)
    public void consumer() {
        String message = redisTemplate.opsForList().rightPop("queue");
        System.out.println("-----------消费者------------>消费了:" + message);
    }
}


  • 入口类
package com.mrcoder.sbredisproducerconsumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class SbRedisProducerConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SbRedisProducerConsumerApplication.class, args);
    }

}


运行

-----------消费者------------>消费了:消息 Mon Sep 02 15:44:42 CST 2019
-----------生产者------------>生产了:消息 20190902155016
-----------生产者------------>生产了:消息 20190902155046

项目地址:

https://github.com/MrCoderStack/SpringBootDemo/tree/master/sb-redis-producer-consumer

请关注我的订阅号

订阅号.png

详解大数据领域Kafka的消息生产与消费机制 Broker收到消息后,会做什么?Leader副本先写入消息(Append to Log);Follower副本从Leader同步消息(Fetch Request);当所有ISR副本都写入消息后,Leader向生产者返回确认响应,包含Topic、Partition、Offset)。Offset的作用:每个Partition中的消息都有一个唯一的Offset(偏移量),用于标记消息的位置(比如Offset=100表示这是Partition中的第101条消息)。 阅读详情

相关推荐

置顶必读(1) |《滚雪球学 Spring Boot 4.x》专栏目录导航篇(持续更新中)!

🏆 本文收录于 《滚雪球学 Spring Boot 4.x》 专栏。 本专栏面向 有一点 Java 基础,但没有系统学过 Spring Boot 的读者,采用“滚雪球式学习法”:先跑通、再理解、再重构、再上线,最终带你从第一个 Hello API 一路完成一个可部署、可监控、可扩展的后端项目。

**My Coding Family** 8万+

【Springboot+Redis】Springboot+Redis实现消息队列(生产者/消费者、发布订阅模式)

  一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式。利用redis这两种场景的消息队列都能够实现。 定义:         生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列,谁先抢到消息谁就会从队列中取走消息;即对于每个消息只能被最多一个消费者拥有。         发布者订阅者模式:发布者生产消息放到队列里,多个监听队列的消费者都会收到同一份消...

niuchenliang524的博客 4万+

SDR实战(四)-AD9361使用手册(三)

本节定义了并行数据端口和串行外设接口(SPI),它们使得AD9361与基带处理器(BBP)之间能够传输数据和控制/状态信息。图63展示了这些接口,并提供了AD9361和BBP在宽带无线系统中使用方式的高级概述。数据接口以两种模式之一运行:兼容标准CMOS模式或兼容低压差分信号(LVDS)模式。每个接口都具有以下部分描述的独特特性。使用CMOS模式时:保持了单端-CMOS逻辑兼容性。可以使用一个或两个数据端口。使用两个端口可以提高数据吞吐量。

hutx0924的博客 6242

Redis实现消息队列的方式

Redis实现队列的几种方式

RHHcainiao的博客 1840

武汉大学朱玉贤院士团队再发Nature Genetics,阐述棉花独特折叠胚胎形成的分子调控与演化机制

武汉大学朱玉贤院士团队再发Nature Genetics,阐述棉花独特折叠胚胎形成的分子调控与演化机制。

Pangenes的博客 1334

RK3588上rknn_toolkit_lite2报错解决:手把手教你更新librknnrt.so的正确姿势

本文针对在RK3588平台上使用rknn_toolkit_lite2时遇到的“Invalid RKNN model version”等常见错误,提供了完整的诊断与解决方案。文章深入剖析了RKNN生态系统各组件(如librknnrt.so、RKNN Server)版本不兼容的根源,并手把手指导如何安全、正确地更新librknnrt.so运行时库,确保AI模型在RK3588 NPU上实现高效推理。

weixin_29189003的博客 518

Redis实现发布订阅功能

本文通过Redis实现类似于消息中间件MQ的消息队列功能,生产者消费者生产者生产消息,消费者通过订阅的Topic去消费消息。

SmallCat0912的博客 2536

适合小白的超详细yolov8环境配置+实例运行教程,从零开始教你如何使用yolov8训练自己的数据集(Windows+conda+pycharm)

yolov8源码下载地址:GitHub - ultralytics/ultralytics: NEW - YOLOv8 🚀 in PyTorch > ONNX > OpenVINO > CoreML > TFLiteyolov8使用文档: Home - Ultralytics YOLOv8 Docs教学视频参考: 包会!YOLOv8训练自己的数据集_哔哩哔哩_bilibili先用conda prompt创建一个虚拟环境,我的叫yolov8, python版本用3.10 源码地址:GitHub - ul

CV在读 25万+

RabbitMQ 消息队列:生产者与消费者实现详解

在分布式系统中,消息队列(Message Queue, MQ)是一种重要的组件,用于解耦系统、异步处理任务以及实现系统间的通信。RabbitMQ 是一个流行的开源消息代理软件,它实现了高级消息队列协议(AMQP)。在本文中,我们将通过 Java 示例来演示如何使用 RabbitMQ 的生产者和消费者模型。

hs_1024的博客 1957

ArcGIS中根据DEM和地形起伏度进行地貌分类划分

大家好我是GIS蒲公英,数字高程模型(digital elevation model, DEM)经常都被用到专题地图的底图中,下面来我们来交流一下仅选择海拔和地形起伏度两个指标,用DEM来进行地貌类型的自动判别划分

GIS蒲公英的博客 3万+

【C++/嵌入式梳理】bootloader

【C++/嵌入式笔试面试八股】bootloader

Hi 1207

33.1从零开始学springboot-一文读懂消息队列-发布订阅(附redis实现)

前言 实际生产中,我们经常会碰到这样的场景: 业务方触发了某些预料之中的bug,(比如项目中调用了第三方的服务,但是第三方的服务出问题导致无法访问,这类错,我们往往不会直接提示用户,而是选择屏蔽此类错误,写入错误日志),我们处理此类bug往往需要去生产导出日志记录,然后排查,最后找到第三方服务的提供者去解决问题. 那么,与其等“被动”业务反馈,能不能让这类问题“主动”推送给开发呢? 我们能不做个“...

CTO技术的博客 547

Android 13.0 开机启动优化之PMS扫描apk耗时相关功能优化

在android13.0的系统rom定制化开发中,在系统中开发产品时,会根据客户要求内置第三方app,这时如果内置app过多,或者安装的app过多,在系统开机的过程中 在pms扫描安装app的时候,就会比较耗时,这时候就需要优化下pms扫描安装app这块的功能代码,用多线程来实现pms扫描安装app,来加快开机时间,接下来 来实现这个功能

安卓兼职framework和app工程师的博客 1333

SpringBoot中实现Redis Stream队列

本文介绍了基于Spring Boot 2.6.3和Redis 5.0.1实现Redis Stream消息队列的方法。主要内容包括:1. 环境配置(JDK1.8、Redis依赖引入);2. RedisStreamUtil工具类封装,提供消费组创建、消息读写等功能;3. 消息生产者实现,通过Controller接口发送消息到"mystream"队列;4. 消费者监听器配置,使用StreamMessageListenerContainer实现消息监听和自动ACK;5. Redis序列化配置和线

m0_53265725的博客 181

强化学习与行为树的融合在游戏编程中的应用

在游戏中,我们可以将游戏的状态作为智能体的状态,将游戏的奖励作为强化学习中的奖励信号,从而训练智能体在游戏中做出最佳决策。强化学习通过试错学习来优化角色的决策策略,而行为树提供了一种灵活的方式来组合和调整不同的行为。行为树可以灵活地调整和组合不同的行为,以适应游戏中不同的情境和目标。在游戏开发中,强化学习和行为树是两种常见的技术,它们被广泛应用于游戏智能的实现。接下来,我们可以定义一个具体的行为树(BehaviorTree),该行为树由一系列节点组成,每个节点代表一个特定的行为或决策。

TechO_O的博客 678

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【SpringBoot框架篇】22.集成RocketMQ实现消息发布和订阅

集成RocketMQ实现消息的发布和订阅

皓亮君的博客 6130

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【SpringBoot框架篇】35.kafka环境搭建和收发消息

搭建kafka环境,在springboot中使用kafka创建主题、生产消息和消费消息

皓亮君的博客 1942

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Rabbitmq消息队列

​ MQ全称为Message Queue,即消息队列. 它也是一个队列,遵循FIFO原则。RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message Queue Protocol高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法,消息队列在分布式系统开发中应用非常广泛。​ 官方地址:http://www.rabbitmq.com/在之前的模式中,我们创建了一个工作队列。工作队列背后的假设是:每个任务只被传递给一个工作人员。

Casual_Lei的博客 1060

【转】redis 消息队列发布订阅模式spring boot实现

 最近做项目的时候写到一个事件推送的场景。之前的实现方式是起job一直查询数据库,看看有没有最新的消息。这种方式非常的不优雅,反正我是不能忍,由于羡慕本身就依赖redis,刚好redis 也有消息队列的功能,就简单的使用redis 来实现这个消息推送。 之前参考网上的例子,发现全部来自一个地方,spring 官方的一个例子,某些打着“非官方例子”的头号,还是一样就复制了一下官方的例子,怕是自己都...

weixin_33843947的博客 152

【Redis】实战篇之黑马点评 10w字详解

比如数据库密码报错:java: 源值 8 已过时,将在未来发行版中删除原因:项目编译指定的 Java 源码版本为 8,但你当前使用的 JDK 版本较高(JDK11+、JDK17、JDK21)解决:我把1.8改为17报错:java: java.lang.ExceptionInInitializerErrorcom.sun.tools.javac.code.TypeTag :: UNKNOWN解决:修改lombok版本 修改springboot版本 修改MySQL驱动版本 报错:Loading class co

ashiho的博客 824

MQ 学习汇总

MQ 学习汇总 什么是MQ MQ全称为Message Queue,消息队列是应用程序和应用程序之间的通信方法。 MQ的三大主要作用 应用解耦、异步提速、流量削锋 应用解耦 系统的耦合性越高,容错性就越低,可维护性就越低。 异步提速模拟 一个下单操作耗时:20 + 300 + 300 + 300 = 920ms 用户点击完下单按钮后,需要等待920ms才能得到下单响应,太慢 用户点击完下单按钮后,只需等待25ms就能得到下单响应 (20 + 5 = 25ms)。 提升用户体验和系统吞吐量(单位时间内处理

qq_43121074的博客 232

Spring官方demo07 Redis消息队列

项目下载:Demo下载 本小节将教你如何通过Spring Data Redis模块来在Redis上发布、接收消息。 你会建立一个利用StringRedisTemplate来发布消息且利用MessageListenerAdapter来订阅消息的应用。 也许使用Spring Data Redis来发布消息听起来很陌生,但是你会发现,Redis和消息系统有个共同点:noSql。 1、建立...

weixin_30299709的博客 70

Java高级面试题总结4

4、补充:NIO和BIO的核心区别就是NIO采用的是IO多路复用的IO模型,普通的IO用的是阻塞的IO模型。3、类加载器都包含哪些:bootstrap、extension、system。设置Eden区和幸存区比例 -XX:SurvivorRatio。方法区 -XX:PermSize-XX:MaxPermSize。设置新生代和老年代比例 -XX:NewRatio。1、数据处理上,NIO:块;设置堆内存大小 -Xms、-Xmx。2、NIO的通道和缓存区。2、加载、连接、初始化。堆 -Xms、-Xmx。

weixin_40047026的博客 2243

Spring全家桶 、Dubbo、分布式、消息队列后端必备全套开源项目

Spring Cloud Alibaba 注册中心 Nacos 入门》 对应 labx-01-spring-cloud-alibaba-nacos-discovery。《Spring Cloud Alibaba 配置中心 Nacos 入门》 对应 labx-05-spring-cloud-alibaba-nacos-config。《Spring Cloud Alibaba 配置中心 Nacos 入门》 对应 labx-05-spring-cloud-alibaba-nacos-config。

m0_63437643的博客 1020

分享一下2024年总结的最新的java面试八股文,附答案

96、springboot如何通过三级缓存解决循环依赖97、ThreadLocal操作的变量,为什么要手动释放98、强引用,弱引用,软引用区别。42、事务在什么情况下会失效43、怎么解决分布式事务44、不同jvm版本的gc机制45、数据库索引什么情况下失效46、大数据框架。40、什么情况会回表查询、怎样可以防止回表查询41、springboot启动流程。10、正式环境中要是有一个内存溢出你怎么处理11、二叉树、红黑树、b树、b+树。38、怎么解决分布式事务、项目中遇到过没39、聚簇索引、非聚簇索引。

m0_69305074的博客 757

01-项目简介Springboot简介入门配置项目准备

总体课程主要分为4个阶段课程: ------------------------课程介绍------------------------ 01-项目简介Springboot简介入门配置项目准备02-MariaDB主从安装SpringBoot整合MyBatis配置03-MyBatis主从实现代码读写分离应用以及实现04-RocketMQ入门及其使用05-RocketMQ与项目整合06-消息可靠性...

weixin_30562507的博客 231
上一篇: 33.1从零开始学springboot-一文读懂消息队列-发布订阅(附redis实现)
下一篇: 34.从零开始学springboot-mybatis查询字段null值不回显问题
码哥说
博客等级 码龄8年 5645粉丝 172原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码哥说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值