背景:项目中有一个触发+执行动作功能, 当条件被触发后 可以设置时间 延时执行动作.
思考了一下,有以下几种方式:
- Quartz 任务调度框架,更适合周期性的执行任务,对于订单超时未支付,只能采用5分钟一轮询数据库的形式实现
- Timer java原生定时工具,可少量使用,当数据量大时,性能不好控制
- Quartz + Timer 周期轮询(5分钟)数据库,查询出5分钟之内将要超时的订单,然后多线程创建timer完成订单的定时,这种实现方式比较复杂,但是可以在性能和功能方面,是可以实现的
- reids 键空间通知 以下将介绍此种方式
1,加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
2.创建两个类
RedisKeyExpirationListener
package com.star.re.redis;
import org.apache.log4j.Logger;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import com.star.common.utils.RedisUtil;
import com.star.re.utils.RuleFilterThread;
import com.star.re.utils.RuleUtils;
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
private static Logger logger = Logger.getLogger(RedisKeyExpirationListener.class);
/**
* redis key失效,监听
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
// 业务处理 , 注意message.toString()可以获取失效的key
String expiredKey = message.toString();
logger.info(expiredKey + "----动作触发,开始执行");
RuleUtils.executeActionByKey(expiredKey);
}
}
RedisListenerConfig
package com.star.re.redis;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
3.redis配置
在源码目录中有一个模板redis.conf,对它进行改动就可以了。
官方文档中说Keyspace notifications功能默认是关闭的(默认地,Keyspace 时间通知功能是禁用的,因为它或多或少会使用一些CPU的资源),我们需要打开它。打开的方法也很简单,配置属性:notify-keyspace-events
默认配置是这样的:notify-keyspace-events ""
根据文档中的说明:
K Keyspace events, published with __keyspace@<db>__ prefix.
E Keyevent events, published with __keyevent@<db>__ prefix.
g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
$ String commands
l List commands
s Set commands
h Hash commands
z Sorted set commands
x Expired events (events generated every time a key expires)
e Evicted events (events generated when a key is evicted for maxmemory)
A Alias for g$lshzxe, so that the "AKE" string means all the events.
我们配置为:notify-keyspace-events Ex,含义为:发布key事件,使用过期事件(当每一个key失效时,都会生成该事件)。\
然后重启即可.