Redis的事件通知
Redis事件通过 Redis 的订阅与发布功能(pub/sub)来进行分发, 因此所有支持订阅与发布功能的客户端都可以在无须做任何修改的情况下, 使用键空间通知功能。
因为 Redis 目前的订阅与发布功能采取的是发送即忘(fire and forget)策略, 当订阅事件的客户端断线时, 它会丢失所有在断线期间分发给它的事件。
在Spring Boot中,可以通过实现RedisMessageListener
接口来实现Redis键过期回调功能。
Redis事件配置
因为开启redis通知功能需要消耗一些 CPU , 所以在默认配置下, 该功能处于关闭状态。
可以通过修改 redis.conf 文件, 或者直接使用 CONFIG SET 命令来开启或关闭键空间通知功能:
当 notify-keyspace-events 选项的参数为空字符串时,功能关闭。
当参数不是空字符串时,功能开启。
notify-keyspace-events 的参数可以是以下字符的任意组合, 它指定了服务器该发送哪些类型的通知:
输入的参数中至少要有一个 K
或者 E
, 否则的话, 不管其余的参数是什么, 都不会有任何通知被分发。
举个例子, 如果只想订阅键空间中和列表相关的通知, 那么参数就应该设为 Kl
, 诸如此类。
将参数设为字符串"AKE"
表示发送所有类型的通知。
SpringBoot实现
pom中引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.7.14</version>
</dependency>
yml中redis配置
spring:
redis:
host: 192.168.1.111
port: 6379
password: 123456
timeout: 1000
jedis:
pool:
max-active: 10
max-wait: -1ms
max-idle: 8
min-idle: 0
RedisConfig
@Configuration
@EnableCaching
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport {
@Bean
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(
RedisConnectionFactory connectionFactory,
MessageListener messageListener) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
// 设置监听的频道,这里监听了"__keyevent@0__:expired"频道,其中0是Redis数据库的索引
container.addMessageListener(messageListener, new PatternTopic("__keyevent@*__:expired"));
container.addMessageListener(messageListener, new PatternTopic("__keyevent@*__:set"));
container.addMessageListener(messageListener, new PatternTopic("__keyevent@*__:del"));
return container;
}
}
在上述配置中,通过PatternTopic指定监听的Redis键过期事件频道为__keyevent@*__:expired、__keyevent@*__:set、__keyevent@*__:del,并将RedisKeyListener注册到容器中。
分别对应过期、设置、删除事件:
keyevent 是 Redis 中的一种特殊频道,用于发布键空间通知(keyspace notifications)事件。
@0 表示 Redis 数据库的索引。Redis 支持多个数据库,索引从 0 开始,因此 0 表示默认的第一个数据库。
:expired 是事件类型,表示键已过期。
:set是事件类型,表示新增键。
:del是事件类型,表示删除键。
FastJson2JsonRedisSerializer
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
}
}
RedisKeyListener事件监听器,实现MessageListener
接口,并实现onMessage
方法,该方法会在事件发生时被调用
@Component
public class RedisKeyListener implements MessageListener {
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = message.toString();
String str = new String(pattern);
// 在这里添加业务逻辑,比如清除相关数据或发送通知
System.out.println("键:"+str +"--" + expiredKey);
}
}