使用場景:當redis某個key過期的時候懈息,我們希望處理一些業(yè)務(wù)例如發(fā)消息或者取消訂單等,當然也可以使用中間件mq來實現(xiàn)馋没,之前的文章里有寫rocketMq實現(xiàn)消息的通知和消費史翘,這篇文章主要是用redis來實現(xiàn)
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.自定義監(jiān)聽器,需要繼承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,可以做自己的業(yè)務(wù)
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){
// 避免多個服務(wù)監(jiān)聽情況下重復(fù)消費
// 注意:只能獲取失效的key值庐完,不能獲取key對應(yīng)的value值
System.out.println(expiredKey);
}
}
}
我們需要重寫onMessage方法,當有key過期的時候這個方法可以獲取獲取的key徘熔,并處理自己的業(yè)務(wù)
如果我們是多臺機器部署门躯,那么我們還需要加鎖操作,避免消息的重復(fù)消費酷师,這里利用了stringRedisTemplate.opsForValue().setIfAbsent命令可以幫我們完成setnx加鎖的操作讶凉,如果為空set返回true,如果不為空返回false染乌,因為redis是單線程所以可以保證只消費一次,setIfAbsent同時要加上過期時間懂讯,注意redis版本過低的話可能沒有這個方法