简单定时任务解决方案:使用redis的keyspace notifications(键失效后通知事件)
需要注意此功能是在redis 2.8版本以后推出的,因此你服务器上的reids最少要是2.8版本以上;
(A)业务场景:
1、当一个业务触发以后需要启动一个定时任务,在指定时间内再去执行一个任务
2、redis的keyspace notifications 会在key失效后发送一个事件,监听此事件的的客户端就可以收到通知
(B)服务准备:
1、修改reids配置文件(redis.conf)
redis默认不会开启keyspace notifications,因为开启后会对cpu有消耗
备注:
E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;
x:过期事件,当某个键过期并删除时会产生该事件;
配置如下:
notify-keyspace-events "Ex"
2、重启redis就可以了,我们测试一下我们有没有修改成功。
开启一个客户端用来监听:
[test@127.0.0.1 ~]$ redis-cli
127.0.0.1:6379> psubscribe __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
开启一个发送key的客户端:
[test@127.0.0.1 ~]$ redis-cli
127.0.0.1:6379> set testKey 123 PX 100
OK
127.0.0.1:6379>
结果:
[test@127.0.0.1 ~]$ redis-cli
127.0.0.1:6379> psubscribe __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
1) "pmessage"
2) "__keyevent@0__:expired"
3) "__keyevent@0__:expired"
4) "testKey"
这样代表测试成功!
(C)springBoot工程引用
1、配置文件 application.properties加入如下配置
server.port=9999
#redis 配置
spring.redis.host=192.168.122.128
spring.redis.pool.max-active=8
spring.redis.pool.max-idle=8
spring.redis.pool.max-wait=-1
spring.redis.pool.min-idle=0
spring.redis.timeout=3000
spring.redis.password=123456
spring.redis.port=6379
2、在com.xxx.xxx下添加RedisConfiguration类
package com.xxx.xxx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Created by test on 2017/2/12.
*/
@Component
public class RedisConfiguration extends CachingConfigurerSupport {
Logger logger = LoggerFactory.getLogger(RedisConfiguration.class);
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.password}")
private String password;
@Bean
public JedisPool redisPoolFactory() {
logger.info("JedisPool注入成功!!");
logger.info("redis地址:" + host + ":" + port);
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout,password);
return jedisPool;
}
@Bean
RedisMessageListenerContainer keyExpirationListenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
listenerContainer.setConnectionFactory(connectionFactory);
listenerContainer.addMessageListener((message, pattern) -> {
//处理业务逻辑
System.out.println("message = " + message);
}, new PatternTopic("__keyevent@*__:expired"));
return listenerContainer;
}
}
3、具体业务中向redis添加key
/**
* 添加redis秒定时任务
* key
* redis 键
* expireTimeAt
* 过期时间点 如 12:00过期
*/
private void addRedisTimer(String key,Date expireTimeAt) {
try (Jedis jedis = jedisPool.getResource();) {
jedis.pexpireAt(key,expireTimeAt);
}catch (Exception e){
logger.error("addRedisTimer error: ", e);
}
}