redis之mq实现发布订阅模式
概述
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实现发布订阅模式的更多相关文章
- redis实现消息队列&发布/订阅模式使用
在项目中用到了redis作为缓存,再学习了ActiveMq之后想着用redis实现简单的消息队列,下面做记录. Redis的列表类型键可以用来实现队列,并且支持阻塞式读取,可以很容易的实现一个高性 ...
- Redis进阶篇:发布订阅模式原理与运用
"65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?" "那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆 ...
- Spring Data Redis实现消息队列——发布/订阅模式
一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式.利用redis这两种场景的消息队列都能够实现. 定义:生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列, ...
- 15天玩转redis —— 第九篇 发布/订阅模式
本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果 ...
- redis发布/订阅模式
其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果博主发表了文章,那么100个人就会同时收到通知邮件,除了这个 场 ...
- redis的发布订阅模式
概要 redis的每个server实例都维护着一个保存服务器状态的redisServer结构 struct redisServer { /* Pubsub */ // 字典,键为频道, ...
- Redis - 发布/订阅模式
Redis 提供了一组命令可以让开发者实现 “发布/订阅” 模式.“发布/订阅” 可以实现进程间的消息传递,其原理是这样的: “发布/订阅” 模式中包含两种角色,分别是发布者和订阅者.订阅者可以订阅一 ...
- redis的发布订阅模式pubsub
前言 redis支持发布订阅模式,在这个实现中,发送者(发送信息的客户端)不是将信息直接发送给特定的接收者(接收信息的客户端),而是将信息发送给频道(channel),然后由频道将信息转发给所有对这个 ...
- redis消息通知(任务队列/优先级队列/发布订阅模式)
1.任务队列 对于发送邮件或者是复杂计算这样的操作,常常需要比较长的时间,为了不影响web应用的正常使用,避免页面显示被阻塞,常常会将此类任务存入任务队列交由专门的进程去处理. 队列最基础的方法如下: ...
随机推荐
- PHP7安装mysql扩展
1.下载mysql扩展 http://git.php.net/?p=pecl/database/mysql.git;a=summary 2.解压后并使用phpize工具初始化(phpize一般在php ...
- 灵活使用Maven Profile
项目中一直应用Maven的profile特性解决不同环境的部署问题.最近在尝试解决本地调试环境的时候碰到一些问题,顺便仔细研究了一下.因为项目仍然在用普通SpringMVC架构,没有切换到Spring ...
- 史上最全存储引擎、索引使用及SQL优化的实践
史上最全存储引擎.索引使用及SQL优化的实践 1 MySQL的体系结构概述 2. 存储引擎 2.1 存储引擎概述 2.2 各种存储引擎特性 2.2.1 InnoDB 2.2.2 MyISAM 3. 优 ...
- Flask+APScheduler定时任务
1.安装依赖 pip install flask_apscheduler 2.使用定时任务 ```python from flask import Flask from flask_apschedul ...
- [ubuntu][deepin]系统增加自定义开机启动项
[ubuntu][deepin]系统增加自定义开机启动项 进行配置 cd /etc/init.d/ ls vim myScript nginx实例 #! /bin/sh # chkconfig: # ...
- Oracle jdbc 插入 clob blob
Oracle 使用 clob 与 blob 插入一些比较庞大的文本或者文件,JDBC 插入时 也比较简单 表结构 CREATE TABLE test_info ( user_id int NOT NU ...
- 【Java例题】7.6文件题3-文本文件统计
6.文本文件统计.已有一个文本文件文件,请统计数字.大写字母.小写字母.汉字及其它字符出现的次数:然后将这些次数由大到小写到另一个文件之中.说明:将次数为零的过滤掉排序 package chapter ...
- C#的委托事件总结
什么是委托?1.委托是C#中由用户自定义的一个类型.2.类表示的是数据和方法的集合,而委托实际上是一个能持有对某个或某些方法的引用的类.3.与其他的类不同,委托类能拥有一个签名,并且他只能持有与他的签 ...
- 网络编程网络协议篇(osi七层协议)
一 互联网的本质 咱们先不说互联网是如何通信的(发送数据,文件等),先用一个经典的例子,给大家说明什么是互联网通信. 现在追溯到八九十年代,当时电话刚刚兴起,还没有手机的概念,只是有线电话,那么此时你 ...
- c# http Post Get 方法
/// <summary> /// get方式访问webapi /// </summary> /// <param name="url">< ...