概述

Redis不仅可作为缓存服务器,还可用作消息队列,本示例演示如何使用redis实现发布/订阅消息队列。

  • 在Redis中,发布者没有将消息发送给特定订阅者的程序。相反,发布的消息被描述为通道,而不知道(如果有的话)可能有哪些订阅者。
  • 订阅者表示对一个或多个主题感兴趣,只接收感兴趣的消息,而不知道(如果有的话)发布者是什么。
  • 发布者和订阅者的这种解耦可以实现更大的可伸缩性和更动态的网络拓扑。

代码实现

redis实现mq的存储方式很多,可以使用list,zset及stream,这些数据的存储结构决定了怎么消费问题(消息是一次使用、允许多次使用、允许多端消息等),比如使用list,我们可以使用leftPush插入消息,使用rightPop消费消息,实现一条消息一次消息,可以参考与以示例代码:

    @Test
public void testMq() {
for (int i = 0; i < 10; i++) {
redisTemplate.opsForList().leftPush("task-queue", "data" + i);
log.info("插入了一个新的任务==>{}", "data" + i);
}
String taskId = redisTemplate.opsForList().rightPop("task-queue").toString();
log.info("处理成功,清除任务==>{}", taskId);
}

1.配置代码RedisConfig.java

package demo.data.mqRedis.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport { @Autowired
private RedisTemplate redisTemplate; /**
* redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类,方便调试redis
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); //使用StringRedisSerializer来序列化和反序列化redis的ke
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer()); //开启事务
redisTemplate.setEnableTransactionSupport(true); redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate;
} @Bean
MessageListenerAdapter messageListener() {
return new MessageListenerAdapter(new RedisMessageSubscriber());
} @Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, topic()); return container;
} @Bean
MessagePublisher redisPublisher() {
return new RedisMessagePublisher(redisTemplate, topic());
} @Bean
ChannelTopic topic() {
return new ChannelTopic("messageQueue");
}
}

2.定义消息发布接口MessagePublisher.java

package demo.data.mqRedis.config;

public interface MessagePublisher {
void publish(String message);
}

3.发布方实现RedisMessagePublisher.java

package demo.data.mqRedis.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic; /**
* 消息发布方
*/
public class RedisMessagePublisher implements MessagePublisher { @Autowired
private RedisTemplate<String, Object> redisTemplate; @Autowired
private ChannelTopic topic; public RedisMessagePublisher(
RedisTemplate<String, Object> redisTemplate, ChannelTopic topic) {
this.redisTemplate = redisTemplate;
this.topic = topic;
} public void publish(String message) {
redisTemplate.convertAndSend(topic.getTopic(), message);
}
}

4.消息接收方RedisMessageSubscriber.java

package demo.data.mqRedis.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Service; import java.util.ArrayList;
import java.util.List; /**
* 消息订阅方
*/
@Service
@Slf4j
public class RedisMessageSubscriber implements MessageListener { public static List<String> messageList = new ArrayList<>(); public void onMessage(Message message, byte[] pattern) {
messageList.add(message.toString());
log.info("订阅方接收到了消息==>{}", message.toString());
}
}

5.最后贴上application.yml配置

spring:
redis:
host: 127.0.0.1
port: 6379
password:

查看运行结果

1.编写测试用例试发布消息TestRedisMQ.java

package demo.data.mqRedis;

import demo.data.mqRedis.config.RedisMessagePublisher;
import lombok.extern.slf4j.Slf4j;
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.SpringRunner; import java.util.UUID; @RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class TestRedisMQ { @Autowired
RedisMessagePublisher redisMessagePublisher; @Test
public void testMq() {
String message = "Message " + UUID.randomUUID();
redisMessagePublisher.publish(message);
}
}

2.运行结果

2019-09-05 15:51:33.931  INFO 10772 --- [    container-2] d.d.m.config.RedisMessageSubscriber      : 订阅方接收到了消息==>"Message c95959bf-6c30-4801-bc80-0e1e3c9f81bc"

订阅方成功接收到消息了

资料

redis之mq实现发布订阅模式的更多相关文章

  1. redis实现消息队列&发布/订阅模式使用

    在项目中用到了redis作为缓存,再学习了ActiveMq之后想着用redis实现简单的消息队列,下面做记录.   Redis的列表类型键可以用来实现队列,并且支持阻塞式读取,可以很容易的实现一个高性 ...

  2. Redis进阶篇:发布订阅模式原理与运用

    "65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?" "那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆 ...

  3. Spring Data Redis实现消息队列——发布/订阅模式

    一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式.利用redis这两种场景的消息队列都能够实现. 定义:生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列, ...

  4. 15天玩转redis —— 第九篇 发布/订阅模式

    本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果 ...

  5. redis发布/订阅模式

    其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果博主发表了文章,那么100个人就会同时收到通知邮件,除了这个 场 ...

  6. redis的发布订阅模式

    概要 redis的每个server实例都维护着一个保存服务器状态的redisServer结构 struct redisServer {     /* Pubsub */     // 字典,键为频道, ...

  7. Redis - 发布/订阅模式

    Redis 提供了一组命令可以让开发者实现 “发布/订阅” 模式.“发布/订阅” 可以实现进程间的消息传递,其原理是这样的: “发布/订阅” 模式中包含两种角色,分别是发布者和订阅者.订阅者可以订阅一 ...

  8. redis的发布订阅模式pubsub

    前言 redis支持发布订阅模式,在这个实现中,发送者(发送信息的客户端)不是将信息直接发送给特定的接收者(接收信息的客户端),而是将信息发送给频道(channel),然后由频道将信息转发给所有对这个 ...

  9. redis消息通知(任务队列/优先级队列/发布订阅模式)

    1.任务队列 对于发送邮件或者是复杂计算这样的操作,常常需要比较长的时间,为了不影响web应用的正常使用,避免页面显示被阻塞,常常会将此类任务存入任务队列交由专门的进程去处理. 队列最基础的方法如下: ...

随机推荐

  1. Linux vi/vim使用

    vi/vim 基本使用方法 vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令. 1.vi的基本概念 基本上vi ...

  2. 2019牛客暑期多校训练营(第三场)H题目

    题意:给你一个N×N的矩阵,求最大的子矩阵 满足子矩阵中最大值和最小值之差小于等于m. 思路:这题是求满足条件的最大子矩阵,毫无疑问要遍历所有矩阵,并判断矩阵是某满足这个条件,那么我们大致只要解决两个 ...

  3. 【iOS】copy 关键字

    以前没注意过 iOS 的 copy, nonatomic, assign, weak, strong 等关键字. 偏偏今天遇到了一个问题,恰恰是关键字的问题,如图: 之前用的是 assign, 没有用 ...

  4. PHP后门***详解

    说起php后门***我就心有愉季啊前不久一个站就因不小心给人注入了然后写入了小***这样结果大家知道的我就不说了下面我来给大家收集了各种php后门***做法大家可参考. php后门***对大家来说一点 ...

  5. 整理用Java实现数字转化成字符串左边自动补零方法

    Java 中给数字左边补0 (1)方法一 import java.text.NumberFormat; public class NumberFormatTest { public static vo ...

  6. Keil5调试过程中遇到的一些警告和错误

    最近用keil5调试代码出了一些警告与错误,整理如下: 1.warning: #1295-D: Deprecated declaration run_c - give arg types void r ...

  7. 【游记】NOIP2018复赛

    声明 我的游记是一个完整的体系,如果没有阅读过往届文章,阅读可能会受到障碍. ~~~上一篇游记的传送门~~~ 前言 参加完NOIP2018的初赛过后,我有点自信心爆棚,并比之前更重视了一点(也仅仅是一 ...

  8. react学习(二)--元素渲染

    元素用来描述你在屏幕上看到的内容: const element = <h1>Hello, world</h1>; 与浏览器的 DOM 元素不同,React 当中的元素事实上是普 ...

  9. 基于SMS短信平台给手机发送短信

    JAVA发送手机短信,我知道的有三种方式,恰逢项目需求,自己整理了基于SMS的短信发送,其他两种这里就说说一下 使用webservice接口发送手机短信,这个可以使用sina提供的webservice ...

  10. Linux--shell的基本特性--01

    1.bash的基本特性: a) 命令展开:date命令—— 基于date命令创建命令 查看系统时钟:date 查看硬件时钟: clock .hwclock (常常同步系统时钟与硬件时钟) cal 查看 ...