Redis消息通知

Redis消息通知

push channel body
如上是redis发送消息的基本格式, channel:通道信息, body:内容 比如:
publish aaa xxx
publish aaa ttt


向通道aaa发送了两条消息,一条是消息内容是xxx,另一条消息内容是ttt,以上的内容都是在redis-cli中执行的.那么对应的代码在springboot中怎么接收该消息呢

首先需要再redis配置中配置监听器,并设置监听的通道信息

package com.wqeq.test;

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;

/**
 * @description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置
 * 
 */
@Configuration
public class RedisMsgListenConfig {
    @Autowired
    private RedisTestMsgListener redisTestMsgListener;
    /**
     * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
     * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
     * 
     * @param connectionFactory
     * @return
     */
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {

        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        //配置redis消息监听通道
        container.addMessageListener(redisTestMsgListener, new PatternTopic("aaa"));
        container.addMessageListener(redisTestMsgListener, new PatternTopic("__keyevent@2__:del"));
        container.addMessageListener(redisTestMsgListener, new PatternTopic("__keyspace@2__:aaa"));

        return container;
    }
}

这里我们监听了3个通道的消息,分别是
aaa
keyevent@2:del
keyspace@2:aaa

这里使用RedisTestMsgListener的实例来接收消息,可以注意到,这里3个通道使用的同一个消息监听来处理,因为仅作为测试不需要那么麻烦写多个,实际根据自己的业务来决定。

然后接收消息的代码如下

package com.wqeq.test;

import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;

/**
 * 接收来自redis的消息通知
 */
@Component
public class RedisTestMsgListener implements MessageListener {

    private final static Logger logger = LoggerFactory.getLogger(RedisTestMsgListener.class);

    @Override
    public void onMessage(@NotNull Message message, byte[] bytes) {
        //简单输出通道和内容信息
        logger.info("收到消息:"+new String(message.getChannel())+"-->"+new String(message.getBody()));
    }
}

代码ok了,那来跑一遍测试吧
在redis-cli里执行发送简单消息"helloworld",^-^(每个程序员都会心一笑!)

publish aaa helloworld
redis消息推送1 Redis消息通知

查看代码监听的输出结果
redis消息推送结果1 Redis消息通知

从结果可以看到是符合预期的,aaa是我们可以理解的通道,但是另外两个通道比较奇怪keyevent@2:del
keyspace@2:aaa
这个是什么东西?为什么要写这么奇怪的通道?并且也是可以发送的,对应语句如下

publish __keyevent@2__:del aaa
publish __keyspace@2__:aaa del

同样可以收到结果,对应输出如下
消息推送2 Redis消息通知
消息推送2结果 Redis消息通知

结果也是符合预期的。这里为什么要用这样特别的写法,其实这种是系统的自身的发送消息格式,也就是告诉我们虽然可以但是最好不要由私人调用,在写具体业务的时候的发送的消息格式要尽量避开这种写法。

到目前为止可能还有人不知道如何在代码里面发送消息,其实非常简单,直接上代码

redisTemplate.convertAndSend("aaa","hello");

是不是特别简单?那么哪些情况会触发redis自身的消息发送呢,目前已知有redis的事件操作和key操作,比如马上能想到的key的删除,修改,过期等等

现在在来看看这两种写法的具体含义:

如果想知道某个事件的触发是由什么key引起的使用keyevent

publish keyevent@*:event aaa

上面可替换的部分有
*代表第几个库的key触发了事件,redis默认16个库,可以填任何一个数字,也可以直接使用星号代表任何库
event代表了事件,del,expire,rename...
aaa代表消息的发送通道,对应接收需要监控该通道

例子

publish __keyevent@2__:del aaa

所以上面语句表示的意思是redis的2号库触发了删除key事件,然后redis系统会自动发送一条删除事件的消息,消息内容是被删除的key为aaa,然后我们就可以在代码中监听事件的变化,业务上再做对应的处理,该消息事件是作为主体。

如果想知道某个key发生了哪些变化使用keyspace

publish keyspace@*:aaa del

同理上面可替换的部分有
*代表第几个库的key触发了事件
event代表了事件,del,expire,rename...
aaa代表消息的通道

publish __keyspace@2__:aaa del

所以上面语句表示的意思是redis的2号库一个key为aaa发生了改变,该key的改变触发了redis的消息通知,消息内容是该key的具体变化(也就是del),跟前面相比理解主体变化了

当然如上两个推送需要redis自身支持,已知目前redis要支持该功能至少版本要大于2.8.0
其次,这些推送是要占用服务器资源的,所以需要主动开启,开启方式是在redis.conf文件中加上(如果存在则开启)如下代码并重启redis服务器