1. 什么是 Spring Task
Spring Task 是 Spring 框架自带的轻量级定时任务调度模块,它允许开发者通过简单的注解或 XML 配置来声明定时任务,无需引入 Quartz 等第三方调度框架。Spring Task 基于 JDK 自带的 ScheduledExecutorService 实现,具有配置简单、上手快、与 Spring 生态无缝集成的特点,非常适合中小型项目中的定时任务场景。
2. 环境准备
在使用 Spring Task 之前,需要确保项目中已经引入了 Spring 相关依赖。如果使用的是 Spring Boot,只需在 pom.xml 中添加 spring-boot-starter 即可,Spring Boot 会自动装配定时任务所需的组件。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
如果使用的是传统 Spring 项目,则需要引入 spring-context 依赖,并在 XML 配置文件中开启定时任务支持。
3. 开启定时任务支持
3.1 基于注解的方式
在 Spring Boot 中,只需在启动类或任意配置类上添加 @EnableScheduling 注解即可开启定时任务支持。
java
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3.2 基于 XML 的方式
如果是传统 Spring 项目,可以在 XML 配置文件中添加以下配置:
xml
<task:annotation-driven scheduler="taskScheduler"/>
<task:scheduler id="taskScheduler" pool-size="10"/>
4. 核心注解 @Scheduled
@Scheduled 是 Spring Task 的核心注解,标注在方法上即可将该方法声明为定时任务。它支持多种触发方式,下面逐一介绍。
4.1 fixedRate 固定频率
fixedRate 表示从任务开始执行的时间点开始计时,每隔指定时间执行一次,无论上一次任务是否执行完毕。
java
@Component
public class FixedRateTask {
@Scheduled(fixedRate = 5000)
public void execute() {
System.out.println("固定频率任务执行:" + LocalDateTime.now());
}
}
4.2 fixedDelay 固定延迟
fixedDelay 表示上一次任务执行完毕后,再等待指定时间执行下一次任务。这种方式可以避免任务重叠执行。
java
@Component
public class FixedDelayTask {
@Scheduled(fixedDelay = 5000)
public void execute() {
System.out.println("固定延迟任务执行:" + LocalDateTime.now());
}
}
4.3 initialDelay 初始延迟
initialDelay 用于指定任务首次执行的延迟时间,常与 fixedRate 或 fixedDelay 配合使用。
java
@Component
public class InitialDelayTask {
@Scheduled(initialDelay = 10000, fixedRate = 5000)
public void execute() {
System.out.println("首次延迟10秒后执行,之后每5秒执行一次:" + LocalDateTime.now());
}
}
4.4 cron 表达式
cron 表达式是最灵活的触发方式,可以精确到秒级,支持复杂的调度规则。
java
@Component
public class CronTask {
// 每天凌晨 2 点执行
@Scheduled(cron = "0 0 2 * * ?")
public void execute() {
System.out.println("定时任务执行:" + LocalDateTime.now());
}
}
cron 表达式由 6 或 7 个字段组成,依次为:秒、分、时、日、月、周、年(可选)。常用通配符包括 *(任意值)、?(不指定值)、-(区间)、,(枚举)、/(步长)等。
cron表达式在线生成工具 :https://console.encoo.com/lib/cron/index.html
5. 参数化配置
在实际项目中,定时任务的执行时间往往需要根据环境动态调整,此时可以将 cron 表达式配置在配置文件中。
properties
# application.properties
task.cron=0 0 2 * * ?
java
@Component
public class ConfigurableTask {
@Scheduled(cron = "${task.cron}")
public void execute() {
System.out.println("从配置文件读取 cron 表达式的任务执行:" + LocalDateTime.now());
}
}
6. 异步执行与线程池配置
默认情况下,Spring Task 使用单线程调度器,所有定时任务串行执行。如果任务较多或执行时间较长,建议配置线程池以提升执行效率。
java
@Configuration
public class SchedulingConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}
也可以直接在配置文件中设置线程池大小:
properties
spring.task.scheduling.pool.size=10
spring.task.scheduling.thread-name-prefix=scheduling-task-
7. 动态创建定时任务
除了使用注解声明定时任务外,Spring Task 还支持通过 ScheduledTaskRegistrar 或 ThreadPoolTaskScheduler 动态创建和取消定时任务,适用于需要运行时动态调整任务的场景。
java
@Component
public class DynamicTaskService {
@Autowired
private ThreadPoolTaskScheduler taskScheduler;
private ScheduledFuture<?> future;
public void startTask() {
future = taskScheduler.schedule(() -> {
System.out.println("动态任务执行:" + LocalDateTime.now());
}, new CronTrigger("0/5 * * * * ?"));
}
public void stopTask() {
if (future != null) {
future.cancel(true);
}
}
}
8. 注意事项与常见问题
8.1 任务阻塞问题
默认单线程调度器下,如果某个任务执行时间过长,会阻塞其他任务的执行。建议为耗时任务配置独立的线程池,或使用 @Async 注解将任务异步化。
8.2 任务异常处理
定时任务方法中如果抛出未捕获的异常,会导致该任务后续不再执行。建议在方法内部捕获并处理异常,或使用 try-catch 包裹业务逻辑。
8.3 分布式环境下的重复执行
Spring Task 本身不支持分布式锁,在集群部署时同一任务会在多个节点重复执行。如需保证任务只执行一次,可引入 Redis 分布式锁或使用 Quartz 等支持集群调度的框架。
9. 总结
Spring Task 作为 Spring 生态自带的定时任务解决方案,凭借其轻量、易用、与 Spring 无缝集成的特点,能够满足绝大多数常规定时任务需求。通过 @Scheduled 注解可以快速实现基于固定频率、固定延迟和 cron 表达式的任务调度,结合线程池配置和动态任务创建,可以应对更复杂的业务场景。对于分布式环境下的任务调度,则需要结合分布式锁或引入更专业的调度框架。