微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

记录springboot监听redis过期key

一个需求中,需要当redis的key删除或过期的时候往日志表中插入一条对应的记录。那么如何监听redis的过期key呢?
1.首先需要设置redis配置文件
notify-keyspace-events Ex,
或者使用命令 CONfig set notify-keyspace-events Ex。
那么notify-keyspace-events 后面都有哪些参数呢

在这里插入图片描述

输入的参数中至少要有一个K或者E,否则其余参数不会有任何的通知生效。

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;
    }
}

3.自定义一个监听器重写对应的onMessage方法

@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] 举报,一经查实,本站将立刻删除。

相关推荐