在官网的文档介绍中有一行介绍:Redis是一个快速稳定的发布/订阅消息系统。
Redis提供了发布与订阅的功能,可以用于消息的传输,Redis的发布订阅机制包括三部分,发布者、订阅者和Channel(主题或者队列)。

其原生命令以及相关介绍
http://www.redis.cn/topics/pubsub.html 。
Redis可以提供基本的发布订阅功能,但毕竟不像消息队列那种专业级别,所以会存在以下缺点:
redis无法对消息持久化存储,消息一旦被发送,如果没有订阅者接收,数据会丢失。
消息队列提供了消息传输保障,当客户端连接超时或事物回滚的等情况发生时,消息会重新发布给订阅者。redis没有该保障,导致的结果就是在订阅者断线超时或其他异常情况时,将会丢失所有发布者发布的信息。
若订阅者订阅了频道,但自己读取消息的速度很慢的话,那么不断积压的消息会使redis输出缓冲区的体积变得越来越大,这可能使得redis本身的速度变慢,甚至直接崩溃。
首先编写一个监听类PubSubListener,用于实现编码各种操作的业务逻辑
package com.example.springboot.listener;
import redis.clients.jedis.JedisPubSub;
public class PubSubListener extends JedisPubSub {
// 取得订阅的消息后的处理
public void onMessage(String channel, String message) {
System.out.println("收到消息:" + channel + "=" + message);
}
// 初始化订阅时候的处理
public void onSubscribe(String channel, int subscribedChannels) {
System.out.println("初始订阅:" + channel + "=" + subscribedChannels);
}
// 取消订阅时候的处理
public void onUnsubscribe(String channel, int subscribedChannels) {
System.out.println("取消订阅:" + channel + "=" + subscribedChannels);
}
// 初始化按表达式的方式订阅时候的处理
public void onPSubscribe(String pattern, int subscribedChannels) {
System.out.println("初始订阅P:" + pattern + "=" + subscribedChannels);
}
// 取消按表达式的方式订阅时候的处理
public void onPUnsubscribe(String pattern, int subscribedChannels) {
System.out.println("取消订阅P:" + pattern + "=" + subscribedChannels);
}
// 取得按表达式的方式订阅的消息后的处理
public void onPMessage(String pattern, String channel, String message) {
System.out.println("收到消息P:" + pattern + "=" + channel + "=" + message);
}
}其次编码测试类,用户启动订阅,和测试发布消息
package com.example.springboot;
import com.example.springboot.listener.PubSubListener;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
public class RedisSubscribe {
private static final String My_Blog = "Javacui";
private static Jedis jedis;
static {
jedis = new Jedis("127.0.0.1",6379);
jedis.auth("l52u27lv1Jur");
}
/**
* 订阅给定的一个或多个频道的信息
*/
@Test
public void subscribe(){
final PubSubListener listener = new PubSubListener();
jedis.subscribe(listener, My_Blog);
}
/**
* 将信息 message 发送到指定的频道 channel
* 返回值:接收到信息 message 的订阅者数量
*/
@Test
public void publish(){
jedis.publish(My_Blog, "java小强");
System.out.println("客户端发布消息成功");
}
}首先编码消息收到后的业务逻辑代码类
package com.example.springboot.listener;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
/**
* Redis消息业务处理
*/
@Component
public class RedisMessageListener implements MessageListener {
@Override
public void onMessage(Message message, byte[] pattern) {
String body = new String(message.getBody());
String channel = new String(message.getChannel());
System.out.println("接收消息:" + channel + " -> " + body);
}
}其次配置把监听类注入到RedisMessageListenerContainer中,这里可以编码多个监听
package com.example.springboot.config;
import com.example.springboot.listener.RedisMessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
/**
* 配置Redis监听
*/
@Configuration
public class RedisMessageConfig {
/**
* 监听主题
*/
private static final String My_Blog = "Javacui";
/**
* 注入消息监听容器
*/
@Autowired
private RedisMessageListener redisMessageListener;
@Bean
public RedisMessageListenerContainer getRedisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory){
RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
//订阅主题
redisMessageListenerContainer.addMessageListener(new MessageListenerAdapter(redisMessageListener), new PatternTopic(My_Blog));
return redisMessageListenerContainer;
}
}编写一个Controller来模拟发送消息
package com.example.springboot.controller;
import cn.hutool.core.date.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class MessSendController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private static final String My_Blog = "Javacui";
@RequestMapping("/redis/send")
public String sendRedisMess() {
stringRedisTemplate.convertAndSend(My_Blog, "Java小强 " + DateUtil.now());
System.out.println("客户端 消息发送完成");
return DateUtil.now();
}
}END
Java小强
未曾清贫难成人,不经打击老天真。
自古英雄出炼狱,从来富贵入凡尘。
发表评论: