Spring Task 是 Spring 框架提供的任务调度工具,可帮助开发者方便地创建定时执行的任务。
1. 基础使用:基于注解的简单定时任务
步骤 1:启用定时任务支持
在 Spring Boot 主类或配置类上添加@EnableScheduling
注解。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 启用定时任务支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
步骤 2:创建定时任务 Bean
使用@Scheduled
注解标记方法,指定执行周期。
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MyScheduledTasks {
// 每5秒执行一次(fixedRate:上次任务开始后5秒执行下一次)
@Scheduled(fixedRate = 5000)
public void fixedRateTask() {
System.out.println("Fixed Rate Task executed at: " + System.currentTimeMillis());
}
// 上次任务结束后延迟3秒执行下一次
@Scheduled(fixedDelay = 3000)
public void fixedDelayTask() {
System.out.println("Fixed Delay Task executed at: " + System.currentTimeMillis());
}
// 初始延迟1秒后开始,之后每2秒执行一次
@Scheduled(initialDelay = 1000, fixedRate = 2000)
public void initialDelayTask() {
System.out.println("Initial Delay Task executed at: " + System.currentTimeMillis());
}
// 使用Cron表达式:每天早上8点执行
@Scheduled(cron = "0 0 8 * * ?")
public void cronTask() {
System.out.println("Cron Task executed at 8:00 AM daily");
}
}
2. Cron 表达式进阶
Cron 表达式由 6 或 7 个字段组成,依次为:秒 分 时 日 月 周 [年]
。
常用示例
表达式 | 说明 |
---|---|
0 0 12 * * ? | 每天中午 12 点执行 |
0 15 10 * * ? | 每天上午 10:15 执行 |
0 0/5 14 * * ? | 每天下午 2 点到 2:55 每 5 分钟执行 |
0 0 12 ? * WED | 每周三中午 12 点执行 |
0 0 0/1 * * ? | 每小时执行一次 |
3. 异步执行定时任务
默认情况下,所有定时任务在同一个线程中串行执行。若需并行执行,可配置异步支持:
步骤 1:启用异步支持
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync // 启用异步支持
public class AsyncConfig {
// 可自定义线程池配置(可选)
}
步骤 2:标记任务为异步
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class AsyncTasks {
@Async // 异步执行
@Scheduled(fixedRate = 5000)
public void asyncTask() throws InterruptedException {
System.out.println("Async Task started at: " + System.currentTimeMillis());
Thread.sleep(2000); // 模拟耗时操作
System.out.println("Async Task finished at: " + System.currentTimeMillis());
}
}
4. 动态定时任务(高级)
通过实现SchedulingConfigurer
接口,可动态调整任务执行周期。
示例:动态调整 Cron 表达式
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@Configuration
@EnableScheduling
public class DynamicSchedulingConfig implements SchedulingConfigurer {
private String cronExpression = "0/5 * * * * ?"; // 初始每5秒执行一次
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
() -> System.out.println("Dynamic Task executed at: " + System.currentTimeMillis()),
triggerContext -> {
// 动态获取Cron表达式(可从数据库、配置中心获取)
return new CronTrigger(cronExpression).nextExecutionTime(triggerContext);
}
);
}
// 自定义线程池
@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(5);
}
// 动态修改Cron表达式的方法
public void updateCronExpression(String newExpression) {
this.cronExpression = newExpression;
System.out.println("Cron表达式已更新为: " + newExpression);
}
}
5. 错误处理与监控
统一异常处理
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.atomic.AtomicInteger;
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("MyAsyncTask-");
executor.setRejectedExecutionHandler((r, executor1) -> {
System.err.println("任务队列已满,拒绝执行: " + r.toString());
});
executor.initialize();
return executor;
}
// 统一异常处理
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
System.err.println("异步任务执行异常: " + ex.getMessage());
ex.printStackTrace();
};
}
}
6. 分布式环境下的任务调度
在分布式系统中,需避免多节点重复执行同一任务。可使用以下方案:
- Redis 锁:通过 Redis 的原子操作实现任务互斥。
- 分布式任务调度框架:如 Elastic-Job、xxl-job、Quartz 集群。
示例:基于 Redis 实现分布式锁
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class DistributedTask {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String LOCK_KEY = "task:distributed_lock";
private static final long LOCK_TIMEOUT = 30; // 锁超时时间(秒)
@Scheduled(fixedRate = 60000) // 每分钟执行一次
public void distributedTask() {
Boolean locked = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY, "locked", LOCK_TIMEOUT, TimeUnit.SECONDS);
if (locked != null && locked) {
try {
// 获取到锁,执行任务
System.out.println("分布式任务执行中...");
// 业务逻辑...
} finally {
// 释放锁
redisTemplate.delete(LOCK_KEY);
}
} else {
System.out.println("其他节点正在执行任务,当前节点跳过");
}
}
}
总结
- 基础:使用
@EnableScheduling
和@Scheduled
实现简单定时任务。 - Cron 表达式:灵活控制任务执行时间。
- 异步执行:通过
@Async
实现任务并行。 - 动态调整:实现
SchedulingConfigurer
接口动态修改执行周期。 - 分布式场景:使用 Redis 锁或专业框架避免任务重复执行。