使用场景:当redis某个key过期的时候,我们希望处理一些业务例如发消息或者取消订单等,当然也可以使用中间件mq来实现,之前的文章里有写rocketMq实现消息的通知和消费,这篇文章主要是用redis来实现
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
yml配置
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
2.配置文件
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* key过期事件订阅需要
* @param redisConnectionFactory
* @return
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory redisConnectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
return container;
}
}
3.自定义监听器,需要继承KeyExpirationEventMessageListener
@Component
public class RedisListener extends KeyExpirationEventMessageListener {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private final String SET_NX = "setnx:";
public RedisListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
// 获取过期的key,可以做自己的业务
String expiredKey = message.toString();
// 利用redis setIfAbsent命令,如果为空set返回true,如果不为空返回false,类似setnx加锁操作
Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(SET_NX + expiredKey, String.valueOf(System.currentTimeMillis()),10, TimeUnit.SECONDS);
if (aBoolean){
// 避免多个服务监听情况下重复消费
// 注意:只能获取失效的key值,不能获取key对应的value值
System.out.println(expiredKey);
}
}
}
我们需要重写onMessage方法,当有key过期的时候这个方法可以获取获取的key,并处理自己的业务
如果我们是多台机器部署,那么我们还需要加锁操作,避免消息的重复消费,这里利用了stringRedisTemplate.opsForValue().setIfAbsent命令可以帮我们完成setnx加锁的操作,如果为空set返回true,如果不为空返回false,因为redis是单线程所以可以保证只消费一次,setIfAbsent同时要加上过期时间,注意redis版本过低的话可能没有这个方法