简单定时任务解决方案:使用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@__为前缀进行发布; 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加入如下配置
spring.redis.host=127.0.0.1
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;
}
}3、在com.xxx.xxx下创建redisKeyspace包
并创建一个Subscribe.java类
package com.xxx.xxx.redisKeyspace;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import redis.clients.jedis.JedisPubSub;
/**
* Created by test on 2017/2/12.
*/
public class Subscribe extends JedisPubSub {
private static final Log log= LogFactory.getLog(Subscribe.class);
// 初始化按表达式的方式订阅时候的处理
public void onPSubscribe(String pattern, int subscribedChannels) {
log.info("Subscribe-onPSubscribe>>>>>>>>>>>>>>>>>>>>>>>>"+pattern + "=" + subscribedChannels);
}
// 取得按表达式的方式订阅的消息后的处理
public void onPMessage(String pattern, String channel, String message) {
try {
log.info(pattern + "=" + channel + "=" + message);
//在这里写你相关的逻辑代码
}catch (Exception e){
e.printStackTrace();
}
}
}
3、创建SubscribeThread.java线程类 备注:此线程实现了CommandLineRunner,springBoot的CommandLineRunner 可以达到工程已启动就开启一个线程
package com.xxx.xxx.redisKeyspace;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* Created by test on 2017/2/13.
*/
@Component
public class SubscribeThread implements CommandLineRunner {
private Log log= LogFactory.getLog(SubscribeThread.class);
@Autowired
JedisPool jedisPool;
@Override
public void run(String... strings) throws Exception {
Jedis jedis= jedisPool.getResource();
try {
//监听所有reids通道中的过期事件
jedis.psubscribe(new Subscribe(), "*");
} catch (Exception e) {
jedis.close();
e.printStackTrace();
}finally {
jedis.close();
}
}
}
4、具体业务中向redis中添加key
/**
* 添加redis秒定时任务
* @param seconds 秒
*/
private void addRedisTimer(String key,int seconds) {
Jedis jedis = jedisPool.getResource();
try {
if (!jedis.exists(key))
jedis.setex(key,seconds,"");
}catch (Exception e){
logger.error("addRedisTimer error: ", e);
}finally {
jedis.close();
}
}
这样我们就实现了springboot已启动就开启一个线程用来监听reids的keyspace notifications事件,然后接收到事件后处理相应的业务代码
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)