Redis的KeyExpirationEventMessageListener键过期监听器
MessageListener通过监听key过期的Redis keyspace通知,然后通过ApplicationEventPublisher发布RedisKeyExpiredEvent事件的模式进行事件监听和广播。
redis.conf地址:https://github.com/redis/redis/blob/unstable/redis.conf
Redis官方地址:https://redis.io/topics/notifications
一、开启Redis键空间
配置发布哪些类型的键空间通知,允许客户端订阅PUB/SUB频道:
- 通过修改redis.conf配置文件;
- 通过应用程序命令行参数模式;
notify-keyspace-events Ex
notify-keyspace-events选项用于配置Keyspace Notifications,即当Redis数据集发生变化时,它可以发布事件。该选项枚举值由多个字符组成,如下:
- K:Keyspace事件,当某个键的事件发生时发布,发布事件使用__keyspace@__前缀。
- E:Keyevent事件,当某个键的事件发生时发布,但事件类型与Keyspace事件不同。如:键的创建、删除、过期等相关操作(set、del、expired、evicted),发布事件使用__keyevent@__前缀。
- g:通用命令(如:DEL、EXPIRE、RENAME…)触发的事件。
- $:String命令触发的事件。
- l:List命令触发的事件。
- s:Set命令触发的事件。
- h:Hash命令触发的时间。
- z:Zset(Sorted Set)命令触发的事件。
- x:过期时间(每当key过期时生成)。
- e:驱逐时间(当key由于maxmemory策略而被驱逐时生成)。
- n:新key事件。
- t:Stream命令。
- A:g$lshzxetd的别名,表示所有事件。
注意:
- K和E的主要区别在于它们发布的事件的详细信息不同。
- 你可以组合这些字符来指定你感兴趣的事件类型和数据类型。
- 默认情况下,这个选项是关闭的(即没有设置)。
二、事件类型
Keyspace通知是通过为影响Redis数据空间的每个操作发送两种不同类型的事件来实现的,例如,针对数据库0中名为mykey的键的DEL操作将触发两条消息的传递,这与以下两个PUBLISH命令完全等效:
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey
第一个通道监听所有针对key为mykey的时间,另一个通道仅监听key为mykey上的del操作时间。
第一种事件在通道中有keyspace前缀,称为keyspace通知;第二种具有keyevent前缀,称为keyevent通知。
在上面的示例中,为mykey键生成了一个del事件,会产生两条消息:
- keyspace事件通道接收key的事件名称作为消息。
- keyevent事件通道接收key的名称作为消息。
可以只启用一种通知,以便只传递我们感兴趣的事件子集。
三、案例
- 要启用列表和通用命令事件,从事件名称的角度来看,使用如下:
notify-keyspace-events Elg
- 获取订阅频道_keyevent@0_:expired过期的keys,使用如下:
notify-keyspace-events Ex
四、Redis命令行客户端
CONFIG GET notify-keyspace-events
1) "notify-keyspace-events"
2) "xE"
- 修改notify-keyspace-events
CONFIG SET notify-keyspace-events Eg
"OK"
五、KeyExpirationEventMessageListener设置notify-keyspace-events属性后为何无法修改?
org.springframework.data.redis.listener.KeyspaceEventMessageListener#init方法定义了设置notify-keyspace-events属性的方法,如果notify-keyspace-events方法不为空则不允许修改:
public void init() {
if (StringUtils.hasText(keyspaceNotificationsConfigParameter)) {
RedisConnection connection = listenerContainer.getConnectionFactory().getConnection();
try {
//获取notify-keyspace-events属性配置
Properties config = connection.getConfig("notify-keyspace-events");
//判定notify-keyspace-events属性是否有值,无值则允许修改
if (!StringUtils.hasText(config.getProperty("notify-keyspace-events"))) {
//修改notify-keyspace-events属性
connection.setConfig("notify-keyspace-events", keyspaceNotificationsConfigParameter);
}
} finally {
connection.close();
}
}
doRegister(listenerContainer);
}
开源SDK:https://github.com/mingyang66/spring-parent