Spring Boot 定时任务使用指南
1. 启用定时任务
在Spring Boot主类上添加 @EnableScheduling 注解:
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 基本定时任务
2.1 使用 @Scheduled 注解
@Component
public class ScheduledTasks {
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
// 固定延迟执行 - 上一次执行完成后延迟5秒再执行
@Scheduled(fixedDelay = 5000)
public void fixedDelayTask() {
log.info("固定延迟任务执行: {}", new Date());
}
// 固定频率执行 - 每5秒执行一次
@Scheduled(fixedRate = 5000)
public void fixedRateTask() {
log.info("固定频率任务执行: {}", new Date());
}
// 使用Cron表达式 - 每分钟执行一次
@Scheduled(cron = "0 * * * * ?")
public void cronTask() {
log.info("Cron任务执行: {}", new Date());
}
}
3. Cron表达式详解
3.1 Cron表达式格式
秒 分 时 日 月 周 [年]
3.2 常用Cron表达式示例
// 每秒执行一次
@Scheduled(cron = "0/1 * * * * ?")
// 每分钟执行一次
@Scheduled(cron = "0 * * * * ?")
// 每小时执行一次
@Scheduled(cron = "0 0 * * * ?")
// 每天凌晨1点执行
@Scheduled(cron = "0 0 1 * * ?")
// 每周一凌晨1点执行
@Scheduled(cron = "0 0 1 ? * MON")
// 每月1号凌晨1点执行
@Scheduled(cron = "0 0 1 1 * ?")
// 工作日上午9点到下午5点,每半小时执行一次
@Scheduled(cron = "0 0/30 9-17 ? * MON-FRI")
3.3 特殊字符说明
*:匹配所有值?:不指定值(用于日和周,避免冲突)-:范围(如:1-5),:列举多个值(如:1,3,5)/:增量(如:0/5表示从0开始每5个单位)L:最后(如:月的最后一天、周的最后一天)W:工作日#:第几个(如:2#3表示第3个星期二)
4. 高级配置
4.1 配置文件中定义Cron表达式
# application.yml
schedule:
tasks:
backup: "0 0 2 * * ?" # 每天凌晨2点执行备份
cleanup: "0 0 3 * * ?" # 每天凌晨3点执行清理
@Component
public class ConfigurableScheduledTasks {
@Value("${schedule.tasks.backup}")
private String backupCron;
@Value("${schedule.tasks.cleanup}")
private String cleanupCron;
@Scheduled(cron = "${schedule.tasks.backup}")
public void backupTask() {
// 备份逻辑
}
@Scheduled(cron = "${schedule.tasks.cleanup}")
public void cleanupTask() {
// 清理逻辑
}
}
4.2 异步定时任务
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("AsyncTask-");
executor.initialize();
return executor;
}
}
@Component
public class AsyncScheduledTasks {
@Async
@Scheduled(fixedRate = 5000)
public void asyncTask() {
// 异步执行的任务
}
}
4.3 条件执行定时任务
@Component
public class ConditionalScheduledTasks {
@Value("${app.scheduled.enabled:true}")
private boolean scheduledEnabled;
@Scheduled(fixedRate = 5000)
public void conditionalTask() {
if (!scheduledEnabled) {
return;
}
// 任务逻辑
}
}
5. 动态定时任务
5.1 使用 TaskScheduler
@Component
public class DynamicScheduledTasks {
@Autowired
private TaskScheduler taskScheduler;
private ScheduledFuture<?> scheduledFuture;
public void startDynamicTask(Runnable task, String cronExpression) {
stopDynamicTask();
scheduledFuture = taskScheduler.schedule(task,
new CronTrigger(cronExpression));
}
public void stopDynamicTask() {
if (scheduledFuture != null) {
scheduledFuture.cancel(false);
}
}
}
5.2 动态修改Cron表达式
@Component
public class DynamicCronTasks {
private String cronExpression = "0 * * * * ?";
@Scheduled(fixedRate = 10000)
public void dynamicCronTask() {
// 可以动态修改cronExpression
}
public void updateCronExpression(String newCron) {
this.cronExpression = newCron;
}
}
6. 定时任务监控
6.1 任务执行监控
@Component
public class MonitoredScheduledTasks {
private static final Logger log = LoggerFactory.getLogger(MonitoredScheduledTasks.class);
@Scheduled(fixedRate = 5000)
public void monitoredTask() {
long startTime = System.currentTimeMillis();
try {
// 任务逻辑
log.info("任务执行成功");
} catch (Exception e) {
log.error("任务执行失败", e);
} finally {
long endTime = System.currentTimeMillis();
log.info("任务执行耗时: {}ms", endTime - startTime);
}
}
}
6.2 使用 Actuator 监控
# application.yml
management:
endpoints:
web:
exposure:
include: health,info,scheduledtasks
访问 /actuator/scheduledtasks 可以查看所有定时任务信息。
7. 最佳实践
7.1 异常处理
@Component
public class RobustScheduledTasks {
private static final Logger log = LoggerFactory.getLogger(RobustScheduledTasks.class);
@Scheduled(fixedRate = 5000)
public void robustTask() {
try {
// 任务逻辑
} catch (Exception e) {
log.error("定时任务执行异常", e);
// 发送告警通知
}
}
}
7.2 避免任务重叠
@Component
public class NonOverlappingTasks {
private volatile boolean isRunning = false;
@Scheduled(fixedRate = 5000)
public void nonOverlappingTask() {
if (isRunning) {
log.warn("上一次任务尚未完成,跳过本次执行");
return;
}
isRunning = true;
try {
// 任务逻辑
} finally {
isRunning = false;
}
}
}
7.3 使用分布式锁
@Component
public class DistributedScheduledTasks {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Scheduled(fixedRate = 5000)
public void distributedTask() {
String lockKey = "scheduled:task:lock";
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "locked", Duration.ofMinutes(5));
if (Boolean.TRUE.equals(locked)) {
try {
// 任务逻辑
} finally {
redisTemplate.delete(lockKey);
}
}
}
}
8. 常见问题
8.1 定时任务不执行
- 检查是否添加了
@EnableScheduling注解 - 确认任务类是否被Spring管理(
@Component等注解) - 检查Cron表达式是否正确
8.2 任务执行时间不准确
- 系统时间可能不准确
- 服务器负载过高导致延迟
- 任务执行时间过长影响下次执行
8.3 内存泄漏
- 长时间运行的定时任务要注意资源释放
- 避免在定时任务中创建大量对象
- 及时关闭数据库连接等资源
9. 总结
Spring Boot的定时任务功能强大且易于使用,通过 @Scheduled 注解可以快速实现各种定时需求。在实际应用中,需要注意异常处理、任务重叠、分布式环境下的执行等问题,确保定时任务的稳定性和可靠性。
5 0
评论 (0)
请先登录后再评论
暂无评论