当前位置:   article > 正文

Redis的键空间监听功能_redis监听

redis监听

Redis 键空间通知

一、keyspace介绍

keyspace(键空间通知)针对指定key发生的一切改动,推送给订阅的客户端,侧重于针对指定key的操作

键空间通知监听格式:__keyspace@<db>__:<key>

二、事件通知配置

默认情况下,键空间事件通知被禁用,因为虽然不太明智,但该功能会使用一些 CPU 功率。notify-keyspace-events有两种配置方式

  • 通过redis.conf配置
  • 通过config set 启用通知,重启失效
例:config set notify-keyspace-events “KEA”
  • 1

将参数设置为空字符串会禁用通知。为了启用该功能,使用由多个字符组成的非空字符串,其中每个字符都有特殊含义

字符发送的通知
K键空间通知,所有通知以 __keyspace@<db>__ 为前缀
E键事件通知,所有通知以__keyevent@<db>__为前缀
gdelexpirerename 等类型无关的通用命令的通知
$string命令的通知
llist命令的通知
sset命令的通知
hhash命令的通知
zzset命令的通知
e驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送
A参数 g$lshzxe 的别名

至少KE应该出现在字符串中,否则无论字符串的其余部分如何,都不会传递任何事件。

例如,要仅启用列表的键空间事件,配置参数必须设置为Kl,等等。

您可以使用该字符串KEA来启用所有类型的通知

三、不同命令生成的事件

具体的看官方文档:Redis 键空间通知,这里举几个例子:

  • DEL为每个已删除的键生成一个del事件。
  • RENAME生成两个事件,一个rename_from针对源键的事件,一个rename_to针对目标键的事件。
  • MOVE生成两个事件,一个move_from针对源键的事件,一个move_to针对目标键的事件。
  • COPY生成一个copy_to事件。
  • EXPIRE及其所有变体(PEXPIREEXPIREATPEXPIREATexpire在使用正超时(或未来时间戳)调用时都会生成一个事件。请注意,当使用过去的负超时值或时间戳调用这些命令时,键将被删除,并且仅del生成一个事件。

四、客户端测试

Redis键空间监听的本质是通过订阅与键相关的消息通知来实现的。当一个Redis键空间的事件发生时,Redis会将事件信息发送到相应的频道(channel),而订阅了该频道的客户端就会接收到这些消息通知。

1.打开redis客户端连接,然后设置所有类型事件都通知

C:\Users\Lenovo>redis-cli
127.0.0.1:6379> config set notify-keyspace-events "KEA"
OK
127.0.0.1:6379>
  • 1
  • 2
  • 3
  • 4

2.订阅一个频道,配置key为qqq:*就会触发通知

# PSUBSCRIBE命令用于订阅一个或多个符合指定模式的频道(channel),支持通配符模式
127.0.0.1:6379> PSUBSCRIBE __keyspace@*__:qqq:*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyspace@*__:qqq:*"
3) (integer) 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

3.新开一个客户端

C:\Users\Lenovo>redis-cli
127.0.0.1:6379> set qqq:111 222
OK
127.0.0.1:6379>
  • 1
  • 2
  • 3
  • 4

结果:可以看到只要qqq:*的发生了变动,就会触发通知
在这里插入图片描述

在这里插入图片描述

五、Springboot整合Redis键空间监听

5.1 方式一

1.引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>2.5.4</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.配置redis

server.port=8080

spring.redis.port=6379
spring.redis.host=127.0.0.1
  • 1
  • 2
  • 3
  • 4

3.配置监听器

@Slf4j
@Component
public class RedisListener implements MessageListener {

    @Override
    public void onMessage(Message message, byte[] pattern) {
        System.out.println(message.toString());
        String body = new String(message.getBody());
        System.out.println(body);
        String channel = new String(message.getChannel());
        System.out.println(channel);

        int index = channel.indexOf(":");
        String key = channel.substring(index + 1); // 找到第一个冒号的位置,冒号后面就是key

        log.info("redis key: {} , channel: {}", key, channel);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

4.开启监听以及配置监听范围

@Component
public class RedisContainer {
    
    @Autowired
    RedisListener redisListener;
    @Autowired
    private TaskExecutor redisListenerContainerTaskExecutor;

    private static final Topic TOPIC_ALL_KEYSPACE = new PatternTopic("__keyspace@*__:*");
    
    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory factory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        // __keyspace@*__:* 可以配置一个也可配置多个
        container.addMessageListener(redisListener, TOPIC_ALL_KEYSPACE);
        container.setTaskExecutor(redisListenerContainerTaskExecutor);
        return container;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

5.测试
在这里插入图片描述

5.2 方式二

1.增加redisTemplate配置

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂
        template.setConnectionFactory(connectionFactory);
        // 创建JSON序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置Key的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 设置Value的序列化
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(jsonRedisSerializer);
        // 返回
        return template;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

2.使用@PostConstruct,在项目启动时动态注入容器

@Slf4j
@Component
public class service {

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private TaskExecutor redisListenerContainerTaskExecutor;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final Topic TOPIC_ALL_KEYSPACE = new PatternTopic("__keyspace@*__:*");

    @PostConstruct
    void init(){
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();

        // 创建redis监听器
        MessageListener listener = (message, pattern) -> {
            System.out.println("message: " + message.toString());
            String body = new String(message.getBody());
            System.out.println("body: " + body);
            String channel = new String(message.getChannel());
            System.out.println("channel: " + channel);

            int index = channel.indexOf(":");
            String key = channel.substring(index + 1); // 找到第一个冒号的位置,冒号后面就是key

            log.info("redis key: {} , channel: {}", key, channel);
        };

        // 创建redis监听适配器
        MessageListenerAdapter listenerAdapter = new MessageListenerAdapter(listener);

        // 创建redis消息监听容器
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisTemplate.getConnectionFactory());
        container.addMessageListener(listenerAdapter, TOPIC_ALL_KEYSPACE);
        container.setTaskExecutor(redisListenerContainerTaskExecutor);

        // redis消息监听容器注入到spring中
        BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RedisMessageListenerContainer.class, () -> container);
        defaultListableBeanFactory.registerBeanDefinition("redisMessageListenerContainer", listenerBeanDefinitionBuilder.getBeanDefinition());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

3.结果一样
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/925156
推荐阅读
相关标签
  

闽ICP备14008679号