說明
redis key過期監聽通知一定要 開啓key過期通知功能。
事件通過 Redis 的訂閱與發佈功能(pub/sub)來進行分發,故需要訂閱 __keyevent@0__:expired 這個topic通道
解釋:keyevent@2:expired
__keyevent 必須以此開頭;
@2 表示監聽第二個數據庫;
:expired 表示過期事件
1、redis 開啓key過期通知
1、修改 redis.conf 文件 ,編輯/etc/redis/redis.conf文件,添加或啓用以下內容(過期通知):
配置詳解:
字符 發送通知 K 鍵空間通知,所有通知以 keyspace@ 爲前綴,針對Key E 鍵事件通知,所有通知以 keyevent@ 爲前綴,針對event g DEL 、 EXPIRE 、 RENAME 等類型無關的通用命令的通知 $ 字符串命令的通知 l 列表命令的通知 s 集合命令的通知 h 哈希命令的通知 z 有序集合命令的通知 x 過期事件:每當有過期鍵被刪除時發送 e 驅逐(evict)事件:每當有鍵因爲 maxmemory 政策而被刪除時發送 A 參數 g$lshzxe 的別名,相當於是All 將
notify-keyspace-events ""
改爲notify-keyspace-events "Ex"
然後、重啓redis , 即可測試失效事件的觸發, 監聽獲取的值爲 key
2、或者登陸redis-cli之後,輸入以下命令:
config set notify-keyspace-events Ex
需要的jar包
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.4.RELEASE</version>
</dependency>
配置文件
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
......
default-lazy-init="false">
<context:property-placeholder location="classpath:redis.properties"
ignore-unresolvable="true"/>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="1000"/>
<property name="minIdle" value="1000"/>
<property name="maxTotal" value="100"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="127.0.0.1"
p:port="6379"
p:pool-config-ref="jedisPoolConfig"
p:use-pool="true"
p:database="${redis.database}"/>
<bean id="RedisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory"
p:keySerializer-ref="stringRedisSerializer"
p:valueSerializer-ref="JdkSerializationRedisSerializer"/>
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<bean id="JdkSerializationRedisSerializer"
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="com.mmall.concurrency.listener.RedisKeyExpiredListener"/>
</constructor-arg>
</bean>
<bean id="redisContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="messageListeners">
<map>
<entry key-ref="messageListener">
<list>
<!-- <bean class="org.springframework.data.redis.listener.ChannelTopic">-->
<!-- <constructor-arg value="__keyevent@1__:expired" />-->
<!-- </bean>-->
<!-- <bean class="org.springframework.data.redis.listener.PatternTopic">-->
<!-- <constructor-arg value="*" />-->
<!-- </bean>-->
<!-- <bean class="org.springframework.data.redis.listener.PatternTopic">-->
<!-- <constructor-arg value="'__key*__:*" />-->
<!-- </bean>-->
<bean class="org.springframework.data.redis.listener.ChannelTopic">
<constructor-arg value="__keyevent@2__:expired"/>
</bean>
</list>
</entry>
</map>
</property>
</bean>
</beans>
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
/**
* redis監聽
* 監聽類需要實現MessageListener,監聽到redis key過期的時候會自動執行到onMessage方法
* @version 1.0
*/
@Slf4j
public class RedisKeyExpiredListener implements MessageListener {
private static final String FAIL_KEY = "fail:key";
@Autowired
private TestService testService;
@Override
public void onMessage(Message message, byte[] bytes) {
String expiredKey = message.toString();// 獲取失效的key
log.info("=========>失效的key:{}", expiredKey);
if (expiredKey.startsWith(FAIL_KEY )) {
// 進行相應的業務處理....
}
}
}
上面就可以完成監聽的功能!!!!
上面的代碼還可以改寫成下面的形式
@Component(value ="SERVICE_NAME")
@Slf4j
public class RedisKeyExpiredListener implements MessageListener {
private static final String FAIL_KEY = "fail:key";
@Autowired
private TestService testService;
@Override
public void onMessage(Message message, byte[] bytes) {
String expiredKey = message.toString();// 獲取失效的key
log.info("=========>失效的key:{}", expiredKey);
if (expiredKey.startsWith(FAIL_KEY )) {
// 進行相應的業務處理....
}
}
}
import com.mmall.concurrency.listener.RedisKeyExpiredListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
/**
* redis監聽容器
* @author 12706
*/
@Configuration
public class RedisConfig {
@Autowired
@Qualifier(value = "SERVICE_NAME")//指定的是自己寫的RedisMessageListener
private RedisKeyExpiredListener redisKeyExpiredListener;
@Autowired
private RedisTemplate redisTemplate;
@Bean
public RedisMessageListenerContainer container(MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisTemplate.getConnectionFactory());
container.addMessageListener(listenerAdapter, new PatternTopic("__keyevent@0__:expired"));
//這裏是監聽redis第一個庫裏面key的過期
return container;
}
@Bean
public MessageListenerAdapter listenerAdapter() {
return new MessageListenerAdapter(redisKeyExpiredListener);
}
}