Redis(键过期)实现定时任务

第一步: 单独注册一个RedisTemplate到spring boot中,连接redis的1号数据库

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import java.time.Duration;

/**
 * redis第二连接库配置
 */
@Configuration
public class RedisMoreDateConfig {


    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    //    @Value("${spring.redis.password}")
//    private String password;
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public GenericObjectPoolConfig getPoolConfig() {
        // 配置redis连接池
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxIdle(3);
        poolConfig.setMinIdle(0);
        poolConfig.setMaxWaitMillis(-1);
        return poolConfig;
    }


    @Bean(name = "redisTemplateOne")
    public StringRedisTemplate getRedisTemplate() {
        return getStringRedisTemplate(1);
    }


    private StringRedisTemplate getStringRedisTemplate(int database) {
        // 构建工厂对象
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(host);
        config.setPort(port);
//        config.setPassword(RedisPassword.of(password));
        LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .commandTimeout(Duration.ofSeconds(6000))
                .poolConfig(getPoolConfig())
                .build();
        LettuceConnectionFactory factory = new LettuceConnectionFactory(config, clientConfig);
        // 设置使用的redis数据库
        factory.setDatabase(database);
        // 重新初始化工厂
        factory.afterPropertiesSet();
        return new StringRedisTemplate(factory);
    }


    /**
     * 监听key过期事件
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        return container;
    }

    /**
     * 指定监听库
     *  监听redis的1号数据库的所有键的过期时间
     */
    @Bean
    public ChannelTopic expiredTopic() {
        return new ChannelTopic("__keyevent@1__:expired");
    }

}

第二步:

什么是redis键空间?
Redis的键空间通知:keyspace notifications
这个功能是在2.8版本后加入的,在客户端通过订阅鸡汁,来接收那些以某种方式改变了redis数据空间的事件通知。
比如说,改变key的命令;所有在0号库过期的key;

事件类型
改变redis数据空间的每个操作,键空间通知都会发送两个不同的事件。
比如在1号数据库,执行 del zhangsan 的操作,将会触发两个消息:

1、keyevent@1:del zhangsan
2、keyspace@1:zhangsan del

keyspace是对所有zhangsan的key操作进行监听的。

keyevent是对所有执行成功的del操作进行监听,
如果有订阅者订阅监听了他,则会收到zhangsan返回的通知。

我就是利用了可以接收某个库过期的key这个操作,完成了这个定时任务。
而这个功能是可以通过redis配置来实现的,下面来说下到底怎么修改这个配置。

redis配置
因为键空间通知会消耗一定的CPU时间,所以在默认情况下,redis是关闭这个功能的,我们需要手动修改redis.conf来修改此功能的开启状态。

找到配置中 # notify-keyspace-events去掉注释,然后重新启动redis就可以了,easy吧?

这条配置,是需要在后面加多个指定的字符组成,来代表其不同的功能:

K:keyspace事件,事件以__keyspace@<库名>__为前缀进行发布;

E:keyevent事件,事件以__keyevent@<库名>__为前缀进行发布;

g:一般性的,非特定类型的命令,比如del,expire,rename等;

$:字符串特定命令;

l:列表特定命令;

s:集合特定命令;

h:哈希特定命令;

z:有序集合特定命令;

x:过期事件,当某个键过期并删除时会产生该事件;

e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;

A:g$lshzxe的别名,因此”AKE”意味着所有事件。

这些选项中,至少要包含K或者E,否则就没啥用了
比如我在这个定时任务中,使用了E和x:notify-keyspace-events Ex
 

第三步: 监控方法

expiredTopic()方法,就可以指定某个库,某个事件,expired就是过期啦。

@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

	/**
     * 失效后回调函数
     * @param message
     * @param pattern
     */
    @SneakyThrows
    @Override
    public void onMessage(Message message, byte[] pattern) {
        super.onMessage(message, pattern);
        String msg = new String(message.getBody(), "UTF-8");
        String channel = new String(message.getChannel(), "UTF-8");

        log.info("Redis-Listener Channel:"+channel+" Listen to the key:"+msg);

        //msg字符串处理,获取想要的key名字....

		//具体的业务处理

		//想要定时,那就继续把key存到redis,结合过期时间
        
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值