做简单定时任务的时候,最烦的就是引入第三方框架,用Quartz吧,太重了,配置复杂;用XXL-Job吧,需要部署调度中心,太麻烦;其实Spring自带的Spring Task就够用了,支持Cron表达式、固定延迟、固定频率,功能简单实用,而且Spring Boot自动配置给你整得明明白白,零配置就能用;但是很多兄弟不知道里面的门道,也不知道咋用@Scheduled注解、配置TaskScheduler、处理异步任务、监控任务这些功能,所以鹏磊今天就给兄弟们掰扯掰扯。
其实Spring Task在Spring Boot里早就支持了,你只要加个@EnableScheduling注解,基本上就能用;但是很多兄弟不知道里面的门道,也不知道咋配置线程池、使用不同的调度方式、处理任务异常、监控任务执行这些高级功能,所以鹏磊今天就给兄弟们掰扯掰扯。
Spring Task基础概念
Spring Task是啥玩意儿
Spring Task是Spring Framework内置的任务调度功能,提供了简单易用的任务调度能力;Spring Task的核心特性包括:
- 简单易用: 使用
@Scheduled注解即可实现定时任务,无需额外配置 - 多种调度方式: 支持Cron表达式、固定延迟、固定频率等多种调度方式
- 自动配置: Spring Boot自动配置TaskScheduler,无需手动配置
- 线程池支持: 支持自定义线程池,可以并发执行多个任务
- Actuator监控: 支持通过Actuator端点监控任务执行情况
- 轻量级: 无需引入第三方依赖,Spring Framework内置
Spring Task的核心概念
- @Scheduled注解: 用于标识定时任务方法,支持多种调度方式
- TaskScheduler: 任务调度器,负责执行定时任务
- ThreadPoolTaskScheduler: 基于线程池的任务调度器实现
- @EnableScheduling: 启用Spring Task功能,必须添加在主配置类上
- Cron表达式: 用于定义复杂的任务执行时间
- 固定延迟(Fixed Delay): 任务执行完成后,延迟固定时间再执行下一次
- 固定频率(Fixed Rate): 任务按固定频率执行,不管上一次是否执行完成
Spring Task和Quartz的区别
- 复杂度: Spring Task简单轻量;Quartz功能强大但复杂
- 持久化: Spring Task不支持持久化;Quartz支持数据库持久化
- 集群: Spring Task不支持集群;Quartz支持集群部署
- 管理界面: Spring Task没有管理界面;Quartz需要自己实现
- 适用场景: Spring Task适合简单定时任务;Quartz适合复杂的企业级任务调度
Spring Task和XXL-Job的区别
- 架构: Spring Task是单体架构;XXL-Job是调度中心+执行器分离架构
- 管理界面: Spring Task没有管理界面;XXL-Job提供Web管理界面
- 动态管理: Spring Task需要重启应用才能修改任务;XXL-Job支持动态管理
- 监控: Spring Task通过Actuator监控;XXL-Job提供完整的监控功能
- 适用场景: Spring Task适合单应用简单任务;XXL-Job适合分布式任务调度
项目搭建和依赖配置
创建Maven项目
首先你得有个Maven项目,用IDEA或者Eclipse都行,或者直接用Spring Initializr生成;项目结构大概是这样:
spring-boot-task-demo/
├── pom.xml # Maven配置文件
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── demo/
│ │ │ ├── Application.java # 启动类
│ │ │ ├── task/ # 任务目录
│ │ │ ├── config/ # 配置类目录
│ │ │ └── controller/ # 控制器目录
│ │ └── resources/
│ │ └── application.yml # 配置文件
│ └── test/
└── README.md
添加Maven依赖
Spring Task是Spring Framework的一部分,Spring Boot已经包含了,不需要额外添加依赖;只需要添加Spring Boot Web Starter即可:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-task-demo</artifactId>
<version>1.0.0</version>
<name>Spring Boot Task Demo</name>
<properties>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Actuator(可选,用于监控) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Lombok(可选,简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启用Spring Task
添加@EnableScheduling注解
在启动类或配置类上添加@EnableScheduling注解,启用Spring Task功能:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* Spring Boot 4 Task示例应用启动类
* @EnableScheduling注解启用Spring Task功能
*
* @author penglei
*/
@SpringBootApplication
@EnableScheduling // 启用Spring Task功能
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
创建定时任务
Cron表达式任务
使用Cron表达式定义任务执行时间:
package com.example.demo.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* Cron表达式任务示例
* 使用@Scheduled注解的cron属性定义任务执行时间
*
* @author penglei
*/
@Slf4j
@Component
public class CronTask {
/**
* 每10秒执行一次
* cron表达式格式: 秒 分 时 日 月 周 [年]
* "0/10 * * * * ?" 表示每10秒执行一次
*/
@Scheduled(cron = "0/10 * * * * ?")
public void executeEvery10Seconds() {
log.info("Cron任务执行: 每10秒执行一次,当前时间: {}", System.currentTimeMillis());
}
/**
* 每天凌晨2点执行
* "0 0 2 * * ?" 表示每天凌晨2点执行
*/
@Scheduled(cron = "0 0 2 * * ?")
public void executeDaily() {
log.info("Cron任务执行: 每天凌晨2点执行");
}
/**
* 每周一上午10点执行
* "0 0 10 ? * MON" 表示每周一上午10点执行
*/
@Scheduled(cron = "0 0 10 ? * MON")
public void executeWeekly() {
log.info("Cron任务执行: 每周一上午10点执行");
}
/**
* 每月1号凌晨1点执行
* "0 0 1 1 * ?" 表示每月1号凌晨1点执行
*/
@Scheduled(cron = "0 0 1 1 * ?")
public void executeMonthly() {
log.info("Cron任务执行: 每月1号凌晨1点执行");
}
}
固定延迟任务
固定延迟任务: 任务执行完成后,延迟固定时间再执行下一次:
package com.example.demo.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 固定延迟任务示例
* fixedDelay: 任务执行完成后,延迟固定时间再执行下一次
*
* @author penglei
*/
@Slf4j
@Component
public class FixedDelayTask {
/**
* 固定延迟5秒执行
* fixedDelay = 5000 表示任务执行完成后,延迟5秒再执行下一次
* 单位: 毫秒
*/
@Scheduled(fixedDelay = 5000)
public void executeWithFixedDelay() {
log.info("固定延迟任务执行: 延迟5秒,当前时间: {}", System.currentTimeMillis());
try {
// 模拟业务处理,耗时2秒
Thread.sleep(2000);
log.info("业务处理完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("任务执行被中断", e);
}
}
/**
* 固定延迟任务,带初始延迟
* initialDelay = 10000 表示应用启动后延迟10秒再开始执行第一次任务
* fixedDelay = 5000 表示任务执行完成后,延迟5秒再执行下一次
*/
@Scheduled(initialDelay = 10000, fixedDelay = 5000)
public void executeWithInitialDelay() {
log.info("固定延迟任务执行: 初始延迟10秒,之后每5秒执行一次");
}
}
固定频率任务
固定频率任务: 任务按固定频率执行,不管上一次是否执行完成:
package com.example.demo.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 固定频率任务示例
* fixedRate: 任务按固定频率执行,不管上一次是否执行完成
*
* @author penglei
*/
@Slf4j
@Component
public class FixedRateTask {
/**
* 固定频率3秒执行一次
* fixedRate = 3000 表示每3秒执行一次,不管上一次是否执行完成
* 单位: 毫秒
*/
@Scheduled(fixedRate = 3000)
public void executeWithFixedRate() {
log.info("固定频率任务执行: 每3秒执行一次,当前时间: {}", System.currentTimeMillis());
try {
// 模拟业务处理,耗时1秒
Thread.sleep(1000);
log.info("业务处理完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("任务执行被中断", e);
}
}
/**
* 固定频率任务,带初始延迟
* initialDelay = 5000 表示应用启动后延迟5秒再开始执行第一次任务
* fixedRate = 3000 表示每3秒执行一次
*/
@Scheduled(initialDelay = 5000, fixedRate = 3000)
public void executeWithInitialDelay() {
log.info("固定频率任务执行: 初始延迟5秒,之后每3秒执行一次");
}
}
使用字符串配置的延迟和频率
支持使用配置文件中的属性值:
package com.example.demo.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 使用配置文件的任务示例
* 支持使用${}占位符从配置文件中读取值
*
* @author penglei
*/
@Slf4j
@Component
public class ConfigurableTask {
/**
* 使用配置文件中的值
* fixedDelayString = "${task.fixedDelay:5000}" 表示从配置文件中读取task.fixedDelay值,如果不存在则使用默认值5000
*/
@Scheduled(fixedDelayString = "${task.fixedDelay:5000}")
public void executeWithConfig() {
log.info("可配置任务执行: 使用配置文件中的延迟时间");
}
/**
* 使用配置文件中的Cron表达式
* cron = "${task.cron:0/10 * * * * ?}" 表示从配置文件中读取task.cron值,如果不存在则使用默认值
*/
@Scheduled(cron = "${task.cron:0/10 * * * * ?}")
public void executeWithCronConfig() {
log.info("可配置Cron任务执行: 使用配置文件中的Cron表达式");
}
}
在application.yml中配置:
# 任务配置
task:
fixedDelay: 5000 # 固定延迟时间(毫秒)
cron: "0/10 * * * * ?" # Cron表达式
Cron表达式详解
Cron表达式格式
Cron表达式由6或7个字段组成,用空格分隔:
秒 分 时 日 月 周 [年]
字段说明:
| 字段 | 允许值 | 允许的特殊字符 | |------|--------|----------------| | 秒 | 0-59 | , - * / | | 分 | 0-59 | , - * / | | 时 | 0-23 | , - * / | | 日 | 1-31 | , - * ? / L W | | 月 | 1-12 或 JAN-DEC | , - * / | | 周 | 0-7 或 SUN-SAT | , - * ? / L # | | 年(可选) | 1970-2099 | , - * / |
特殊字符说明:
*: 匹配所有值?: 不指定值,用于日和周字段-: 指定范围,如10-12表示10到12,: 指定多个值,如MON,WED,FRI表示周一、周三、周五/: 指定增量,如0/15表示从0开始,每15个单位执行一次L: 最后,如L在日字段表示最后一天,在周字段表示周六W: 工作日,如15W表示离15号最近的工作日#: 第几个,如6#3表示第三个周五
常用Cron表达式示例
0 0 12 * * ? 每天12点执行
0 0 12 * * ? 每天12点执行
0 15 10 ? * * 每天10点15分执行
0 15 10 * * ? 每天10点15分执行
0 15 10 * * ? * 每天10点15分执行
0 15 10 * * ? 2005 2005年每天10点15分执行
0 * 14 * * ? 每天14点到14点59分,每分钟执行一次
0 0/5 14 * * ? 每天14点到14点55分,每5分钟执行一次
0 0/5 14,18 * * ? 每天14点到14点55分和18点到18点55分,每5分钟执行一次
0 0-5 14 * * ? 每天14点到14点05分,每分钟执行一次
0 10,44 14 ? 3 WED 3月每周三14点10分和14点44分执行
0 15 10 ? * MON-FRI 周一到周五10点15分执行
0 15 10 15 * ? 每月15号10点15分执行
0 15 10 L * ? 每月最后一天10点15分执行
0 15 10 ? * 6L 每月最后一个周五10点15分执行
0 15 10 ? * 6#3 每月第三个周五10点15分执行
0 0 12 1/5 * ? 每月1号开始,每5天12点执行
0 11 11 11 11 ? 每年11月11号11点11分执行
配置TaskScheduler
默认配置
Spring Boot会自动配置ThreadPoolTaskScheduler,默认使用单线程执行任务;如果需要并发执行多个任务,需要自定义配置。
自定义TaskScheduler配置
创建配置类,自定义TaskScheduler:
package com.example.demo.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.ThreadPoolExecutor;
/**
* TaskScheduler配置类
* 自定义线程池配置,支持并发执行多个任务
*
* @author penglei
*/
@Slf4j
@Configuration
public class TaskSchedulerConfig implements SchedulingConfigurer {
/**
* 配置TaskScheduler
* 实现SchedulingConfigurer接口,自定义任务调度器
*
* @param taskRegistrar 任务注册器
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 设置任务调度器
taskRegistrar.setScheduler(taskScheduler());
log.info("TaskScheduler配置完成,线程池大小: 10");
}
/**
* 创建ThreadPoolTaskScheduler Bean
* 配置线程池大小、线程名前缀、拒绝策略等
*
* @return ThreadPoolTaskScheduler实例
*/
@Bean(destroyMethod = "shutdown")
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
// 设置线程池大小,默认是单线程
scheduler.setPoolSize(10);
// 设置线程名前缀,方便日志追踪
scheduler.setThreadNamePrefix("scheduled-task-");
// 设置等待所有任务完成后再关闭
scheduler.setWaitForTasksToCompleteOnShutdown(true);
// 设置等待时间,单位:秒
scheduler.setAwaitTerminationSeconds(60);
// 设置拒绝策略:调用者运行策略
scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化线程池
scheduler.initialize();
log.info("ThreadPoolTaskScheduler初始化完成,线程池大小: 10");
return scheduler;
}
}
使用配置文件配置TaskScheduler
在application.yml中配置:
spring:
task:
scheduling:
# 线程池大小,默认是单线程
pool:
size: 10
# 线程名前缀
thread-name-prefix: scheduled-task-
# 关闭时是否等待任务完成
shutdown:
await-termination: true
# 等待时间(秒)
await-termination-period: 60s
异步任务执行
使用@Async注解
如果任务执行时间较长,可以使用@Async注解异步执行:
package com.example.demo.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 异步任务示例
* 使用@Async注解使任务异步执行,不阻塞调度线程
*
* @author penglei
*/
@Slf4j
@Component
public class AsyncTask {
/**
* 异步执行的定时任务
* @Async注解使任务在单独的线程中执行,不阻塞调度线程
* 注意: 需要启用@EnableAsync注解
*/
@Async
@Scheduled(fixedRate = 5000)
public void executeAsync() {
log.info("异步任务执行: 线程名称: {}", Thread.currentThread().getName());
try {
// 模拟长时间运行的任务
Thread.sleep(3000);
log.info("异步任务执行完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("异步任务执行被中断", e);
}
}
}
启用@Async支持
在启动类或配置类上添加@EnableAsync注解:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* Spring Boot 4 Task示例应用启动类
*
* @author penglei
*/
@SpringBootApplication
@EnableScheduling // 启用Spring Task功能
@EnableAsync // 启用异步任务支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
配置异步任务执行器
package com.example.demo.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步任务配置类
* 配置异步任务执行器
*
* @author penglei
*/
@Slf4j
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
/**
* 配置异步任务执行器
*
* @return Executor实例
*/
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(5);
// 最大线程数
executor.setMaxPoolSize(10);
// 队列容量
executor.setQueueCapacity(100);
// 线程名前缀
executor.setThreadNamePrefix("async-task-");
// 拒绝策略:调用者运行策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成后再关闭
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间
executor.setAwaitTerminationSeconds(60);
// 初始化
executor.initialize();
log.info("异步任务执行器初始化完成,核心线程数: 5, 最大线程数: 10");
return executor;
}
}
任务异常处理
使用ScheduledTaskExceptionHandler
实现ScheduledTaskExceptionHandler接口处理任务异常:
package com.example.demo.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
/**
* 任务异常处理配置
* 实现SchedulingConfigurer接口,处理任务执行异常
*
* @author penglei
*/
@Slf4j
@Configuration
public class TaskExceptionHandlerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 设置异常处理器
taskRegistrar.setScheduler(taskScheduler());
// 设置异常处理
taskRegistrar.setErrorHandler(throwable -> {
log.error("定时任务执行异常", throwable);
// 这里可以添加异常处理逻辑,比如发送告警、记录日志等
});
}
@Bean(destroyMethod = "shutdown")
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10);
scheduler.setThreadNamePrefix("scheduled-task-");
scheduler.initialize();
return scheduler;
}
}
在任务方法中处理异常
package com.example.demo.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 任务异常处理示例
* 在任务方法中捕获和处理异常
*
* @author penglei
*/
@Slf4j
@Component
public class ExceptionHandlingTask {
/**
* 带异常处理的任务
* 在任务方法中捕获异常,避免任务因为异常而停止
*/
@Scheduled(fixedRate = 5000)
public void executeWithExceptionHandling() {
try {
log.info("任务开始执行");
// 模拟可能抛出异常的业务逻辑
if (Math.random() > 0.5) {
throw new RuntimeException("模拟异常");
}
log.info("任务执行成功");
} catch (Exception e) {
log.error("任务执行失败,异常信息: {}", e.getMessage(), e);
// 这里可以添加异常处理逻辑,比如发送告警、记录日志等
}
}
}
动态管理任务
使用ScheduledTaskRegistrar动态添加任务
package com.example.demo.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
* 动态任务管理服务
* 支持动态添加、删除、暂停、恢复任务
*
* @author penglei
*/
@Slf4j
@Service
public class DynamicTaskService {
@Autowired
private TaskScheduler taskScheduler;
// 存储动态任务
private final Map<String, ScheduledFuture<?>> tasks = new ConcurrentHashMap<>();
/**
* 添加动态任务
*
* @param taskName 任务名称
* @param cronExpression Cron表达式
* @param runnable 任务逻辑
*/
public void addTask(String taskName, String cronExpression, Runnable runnable) {
// 如果任务已存在,先删除
if (tasks.containsKey(taskName)) {
removeTask(taskName);
}
// 创建Cron触发器
CronTrigger trigger = new CronTrigger(cronExpression);
// 调度任务
ScheduledFuture<?> future = taskScheduler.schedule(runnable, trigger);
// 保存任务
tasks.put(taskName, future);
log.info("添加动态任务成功: {}, Cron表达式: {}", taskName, cronExpression);
}
/**
* 删除动态任务
*
* @param taskName 任务名称
*/
public void removeTask(String taskName) {
ScheduledFuture<?> future = tasks.remove(taskName);
if (future != null) {
future.cancel(true);
log.info("删除动态任务成功: {}", taskName);
}
}
/**
* 暂停任务
*
* @param taskName 任务名称
*/
public void pauseTask(String taskName) {
ScheduledFuture<?> future = tasks.get(taskName);
if (future != null) {
future.cancel(true);
log.info("暂停任务成功: {}", taskName);
}
}
/**
* 恢复任务
*
* @param taskName 任务名称
* @param cronExpression Cron表达式
* @param runnable 任务逻辑
*/
public void resumeTask(String taskName, String cronExpression, Runnable runnable) {
addTask(taskName, cronExpression, runnable);
log.info("恢复任务成功: {}", taskName);
}
}
Actuator监控
配置Actuator端点
在application.yml中配置:
spring:
# Actuator配置
actuator:
endpoints:
web:
exposure:
include: health,info,scheduledtasks # 暴露scheduledtasks端点
endpoint:
scheduledtasks:
enabled: true # 启用scheduledtasks端点
访问scheduledtasks端点
# 查看所有定时任务
curl http://localhost:8080/actuator/scheduledtasks
# 返回示例
{
"cron": [
{
"expression": "0/10 * * * * ?",
"nextExecution": {
"time": "2024-12-08T16:30:00Z"
},
"runnable": {
"target": "com.example.demo.task.CronTask.executeEvery10Seconds"
}
}
],
"fixedDelay": [
{
"initialDelay": 0,
"interval": 5000,
"lastExecution": {
"status": "SUCCESS",
"time": "2024-12-08T16:29:55Z"
},
"nextExecution": {
"time": "2024-12-08T16:30:00Z"
},
"runnable": {
"target": "com.example.demo.task.FixedDelayTask.executeWithFixedDelay"
}
}
],
"fixedRate": [
{
"initialDelay": 5000,
"interval": 3000,
"nextExecution": {
"time": "2024-12-08T16:30:03Z"
},
"runnable": {
"target": "com.example.demo.task.FixedRateTask.executeWithFixedRate"
}
}
]
}
最佳实践
- 合理使用线程池: 如果任务较多,建议配置线程池,避免任务阻塞
- 处理任务异常: 在任务方法中捕获异常,避免任务因为异常而停止
- 使用配置文件: 将Cron表达式和延迟时间配置在配置文件中,方便修改
- 避免长时间运行的任务: 如果任务执行时间较长,使用
@Async异步执行 - 合理设置初始延迟: 应用启动时设置初始延迟,避免启动时立即执行任务
- 监控任务执行: 使用Actuator端点监控任务执行情况
- 任务幂等性: 确保任务可以重复执行而不产生副作用
- 避免任务阻塞: 不要在任务中执行长时间阻塞的操作
- 合理选择调度方式: 根据业务需求选择合适的调度方式(Cron、固定延迟、固定频率)
- 日志记录: 在任务中记录详细的日志,方便问题排查
总结
Spring Boot 4整合Spring Task非常方便,只需要添加@EnableScheduling注解就能用;支持Cron表达式、固定延迟、固定频率等多种调度方式;可以自定义TaskScheduler配置线程池;支持异步任务执行;通过Actuator可以监控任务执行情况;兄弟们根据实际需求选择合适的配置,就能轻松搞定简单定时任务了。