赞
踩
keyspace(键空间通知)针对指定key发生的一切改动,推送给订阅的客户端,侧重于针对指定key的操作
键空间通知监听格式:__keyspace@<db>__:<key>
默认情况下,键空间事件通知被禁用,因为虽然不太明智,但该功能会使用一些 CPU 功率。notify-keyspace-events
有两种配置方式
redis.conf
配置config set
启用通知,重启失效例:config set notify-keyspace-events “KEA”
将参数设置为空字符串会禁用通知
。为了启用该功能,使用由多个字符组成的非空字符串,其中每个字符都有特殊含义
字符 | 发送的通知 |
---|---|
K | 键空间通知,所有通知以 __keyspace@<db>__ 为前缀 |
E | 键事件通知,所有通知以__keyevent@<db>__ 为前缀 |
g | del 、expire 、rename 等类型无关的通用命令的通知 |
$ | string 命令的通知 |
l | list 命令的通知 |
s | set 命令的通知 |
h | hash 命令的通知 |
z | zset 命令的通知 |
e | 驱逐(evict )事件:每当有键因为 maxmemory 政策而被删除时发送 |
A | 参数 g$lshzxe 的别名 |
至少K
或E
应该出现在字符串中,否则无论字符串的其余部分如何,都不会传递任何事件。
例如,要仅启用列表的键空间事件,配置参数必须设置为Kl,等等。
您可以使用该字符串KEA
来启用所有类型的通知
具体的看官方文档:Redis 键空间通知,这里举几个例子:
DEL
为每个已删除的键生成一个del
事件。RENAME
生成两个事件,一个rename_from
针对源键的事件,一个rename_to
针对目标键的事件。MOVE
生成两个事件,一个move_from
针对源键的事件,一个move_to
针对目标键的事件。COPY
生成一个copy_to
事件。EXPIRE
及其所有变体(PEXPIRE
、EXPIREAT
、PEXPIREAT
)expire
在使用正超时(或未来时间戳)调用时都会生成一个事件。请注意,当使用过去的负超时值或时间戳调用这些命令时,键将被删除,并且仅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>
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
3.新开一个客户端
C:\Users\Lenovo>redis-cli
127.0.0.1:6379> set qqq:111 222
OK
127.0.0.1:6379>
结果:可以看到只要qqq:*
的发生了变动,就会触发通知
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>
2.配置redis
server.port=8080
spring.redis.port=6379
spring.redis.host=127.0.0.1
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); } }
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; } }
5.测试
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; } }
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()); } }
3.结果一样
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。