在一个需求中,需要当redis的key删除或过期的时候往日志表中插入一条对应的记录。那么如何监听redis的过期key呢?
1.首先需要设置redis配置文件
notify-keyspace-events Ex,
或者使用命令 CONfig set notify-keyspace-events Ex。
那么notify-keyspace-events 后面都有哪些参数呢
2.springboot中配置redis
@Configuration
public class RedisConfig {
@Bean
@Primary
public <T> Redistemplate<String, T> getRedistemplate(RedisConnectionFactory redisConnectionFactory) {
Redistemplate<String, T> redistemplate = new Redistemplate<>();
redistemplate.setConnectionFactory(redisConnectionFactory);
redistemplate.setKeySerializer(new StringRedisSerializer());
redistemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
redistemplate.setHashKeySerializer(new StringRedisSerializer());
redistemplate.setHashValueSerializer(new GenericFastJsonRedisSerializer());
return redistemplate;
}
@Bean
public Redistemplate<Object, Object> redistemplate(RedisConnectionFactory redisConnectionFactory) {
Redistemplate<Object, Object> redistemplate = new Redistemplate<>();
redistemplate.setConnectionFactory(redisConnectionFactory);
redistemplate.setKeySerializer(new StringRedisSerializer());
redistemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
redistemplate.setHashKeySerializer(new StringRedisSerializer());
redistemplate.setHashValueSerializer(new GenericFastJsonRedisSerializer());
return redistemplate;
}
@Bean
public StringRedistemplate stringRedistemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedistemplate stringRedistemplate = new StringRedistemplate();
stringRedistemplate.setConnectionFactory(redisConnectionFactory);
return stringRedistemplate;
}
@Bean
public RedisScript<Boolean> hitMaxScript() {
DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("scripts/hitmax.lua")));
redisScript.setResultType(Boolean.class);
return redisScript;
}
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory redisConnectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.setTaskExecutor(executor());
Topic topic = new PatternTopic(RedisKeyExpirationListener.LISTENER_PATTERN);
container.addMessageListener(new RedisKeyExpirationListener(), topic);
return container;
}
@Bean
public Executor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("V-Thread");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
@Component
public class RedisKeyExpirationListener implements MessageListener {
public static final String LISTENER_PATTERN = "__key*@*__:*";
@Resource
private OperationLimitService operationLimitService;
@Override
public void onMessage(Message message, byte[] pattern) {
System.err.println("触发监听器。。。。。。");
String body = new String(message.getBody());
String channel = new String(message.getChannel());
System.out.println("onMessage >> "+String.format("channel: %s, body: %s, bytes: %s",channel,body,new String(pattern)));
}
}
但上面的service注入的是一个null,猜测原因是监听器的执行早于spring的注入。所以又增加了获取bean的代码
@Slf4j
@Configuration
public class SpringContextHolder implements ApplicationContextAware, disposableBean {
private static ApplicationContext applicationContext = null;
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
assertContextInjected();
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
log.debug("从SpringContextHolder中取出Bean:" + name);
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
log.info("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext);
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
// logger.debug("注入ApplicationContext到SpringContextHolder:{}", applicationContext);
if (SpringContextHolder.applicationContext != null) {
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
}
SpringContextHolder.applicationContext = applicationContext; // NOSONAR
}
/**
* 实现disposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() throws Exception {
SpringContextHolder.clearHolder();
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
if(applicationContext == null) {
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
}
}
}
然后这个bean直接从applicationContext中获取就行了
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。