EXPIRE
命令为任务设置过期时间,当到达设定的时间点时,Redis会自动删除该键,并触发相应的事件。确保你的Redis服务器开启了键空间通知功能。可以通过修改redis.conf
文件添加如下配置:
notify-keyspace-events Ex
或者在运行时动态设置:
CONFIG SET notify-keyspace-events Ex
Ex
表示仅监听键过期的事件。
确保你的pom.xml
中包含以下依赖项:
org.springframework.boot
spring-boot-starter-data-redis
在application.properties
或application.yml
中配置Redis连接信息:
spring.redis.host=localhost
spring.redis.port=6379
创建一个服务类用于调度任务:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class TaskScheduler {
@Autowired
private StringRedisTemplate redisTemplate;
public void scheduleTask(String taskId, long delayInSeconds) {
// 设置任务到Redis中,并指定过期时间
redisTemplate.opsForValue().set(taskId, "taskPayload", delayInSeconds, java.util.concurrent.TimeUnit.SECONDS);
}
}
定义一个监听器来处理过期事件:
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
@Component
public class ExpiredKeyMessageListener implements MessageListener {
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = new String(message.getBody());
System.out.println("Expired key detected: " + expiredKey);
// 根据expiredKey解析任务信息,并执行相应的任务逻辑
}
}
注册该监听器:
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.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
ExpiredKeyMessageListener listener) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listener, new PatternTopic("__keyevent@*__:expired"));
return container;
}
}
如果希望使用注解的方式简化任务调度,可以定义一个自定义注解,并编写Aspect来处理它。
定义注解:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ScheduledTask {
String taskId();
long delayInSeconds();
}
编写Aspect:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ScheduledTaskAspect {
@Autowired
private StringRedisTemplate redisTemplate;
@Around("@annotation(scheduledTask)")
public Object scheduleTask(ProceedingJoinPoint joinPoint, ScheduledTask scheduledTask) throws Throwable {
// 获取方法签名作为任务负载
String methodSignature = joinPoint.getSignature().toString();
// 调度任务到Redis中
redisTemplate.opsForValue().set(scheduledTask.taskId(), methodSignature, scheduledTask.delayInSeconds(), java.util.concurrent.TimeUnit.SECONDS);
return null; // 或者根据需要返回实际结果
}
}
import org.springframework.stereotype.Service;
@Service
public class MyTaskService {
@ScheduledTask(taskId = "task1", delayInSeconds = 60)
public void executeTask() {
System.out.println("Executing task...");
}
}
通过上述步骤,你可以构建一个基于Redis的分布式定时任务系统。根据具体的应用需求,可能还需要进一步调整和优化系统的设计,例如引入任务状态管理、任务失败重试策略等高级特性。