一、基础配置与启用
1.1 启用定时任务功能
在Spring Boot应用中,只需在主类添加@EnableScheduling注解即可启用定时任务支持:
@SpringBootApplication
@EnableScheduling // 关键注解
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
![图片[1]_Spring定时任务详解:@Scheduled注解全指南_知途无界](https://zhituwujie.com/wp-content/uploads/2025/08/d2b5ca33bd20250801100800.png)
1.2 基本任务定义
在任意Spring管理的Bean中,使用@Scheduled标注方法:
@Component
public class MyTask {
@Scheduled(fixedRate = 5000) // 每5秒执行一次
public void task1() {
System.out.println("定时任务执行: " + LocalDateTime.now());
}
}
二、时间表达式详解
2.1 三种基础模式
graph TD
A[@Scheduled] --> B[fixedRate]
A --> C[fixedDelay]
A --> D[cron]
2.1.1 fixedRate模式
@Scheduled(fixedRate = 3000) // 每3秒执行,不考虑任务执行时间
public void fixedRateTask() {
// 任务逻辑
}
2.1.2 fixedDelay模式
@Scheduled(fixedDelay = 4000) // 任务结束后间隔4秒再执行
public void fixedDelayTask() throws InterruptedException {
Thread.sleep(2000); // 模拟耗时任务
System.out.println("任务完成");
}
2.1.3 cron表达式
@Scheduled(cron = "0 15 10 * * ?") // 每天10:15执行
public void cronTask() {
// 每日任务
}
2.2 cron表达式语法
| 字段 | 允许值 | 特殊字符 |
|---|---|---|
| 秒 | 0-59 | , – * / |
| 分 | 0-59 | , – * / |
| 小时 | 0-23 | , – * / |
| 日期 | 1-31 | , – * ? / L W C |
| 月份 | 1-12或JAN-DEC | , – * / |
| 星期 | 1-7或SUN-SAT | , – * ? / L C # |
| 年 | 空或1970-2099 | , – * / |
常用示例:
0 0/5 * * * ?每5分钟0 0 12 * * ?每天中午12点0 15 10 ? * MON-FRI工作日10:15
三、高级配置技巧
3.1 动态配置定时规则
通过${}引用配置文件中的参数:
# application.yml
task:
rate: 5000
cron: "0 0/30 * * * ?"
@Scheduled(fixedRateString = "${task.rate}")
public void configurableTask() {}
@Scheduled(cron = "${task.cron}")
public void configurableCronTask() {}
3.2 初始延迟设置
@Scheduled(initialDelay = 10000, fixedRate = 5000) // 启动10秒后开始,之后每5秒执行
public void delayedTask() {}
3.3 多线程配置
默认情况下,所有定时任务在同一个线程执行。可通过配置TaskScheduler实现并行:
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5); // 线程池大小
scheduler.setThreadNamePrefix("my-scheduler-");
scheduler.initialize();
taskRegistrar.setTaskScheduler(scheduler);
}
}
四、异常处理机制
4.1 任务异常捕获
@Scheduled(fixedRate = 10000)
public void riskyTask() {
try {
// 可能抛出异常的代码
} catch (Exception e) {
logger.error("定时任务执行失败", e);
// 可选:发送告警通知
}
}
4.2 全局异常处理器
@Component
public class ScheduledExceptionHandler implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(1,
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler((thread, ex) -> {
System.err.println("捕获定时任务异常: " + ex.getMessage());
});
return t;
}
}));
}
}
五、生命周期管理
5.1 手动启停任务
@Component
public class DynamicTask {
private final ScheduledFuture<?> future;
private final TaskScheduler scheduler;
public DynamicTask(TaskScheduler scheduler) {
this.scheduler = scheduler;
this.future = scheduler.scheduleAtFixedRate(
this::taskLogic, 5000); // 初始5秒间隔
}
private void taskLogic() {
System.out.println("动态任务执行");
}
public void changeInterval(long newInterval) {
future.cancel(false);
scheduler.scheduleAtFixedRate(this::taskLogic, newInterval);
}
}
5.2 条件化执行
@Scheduled(fixedRate = 60000)
@ConditionalOnProperty(name = "task.enabled", havingValue = "true")
public void conditionalTask() {
// 仅当task.enabled=true时执行
}
六、最佳实践建议
6.1 性能优化方案
- 短任务原则:单任务执行时间应小于间隔时间
- 异步处理:耗时操作应使用
@Async@Scheduled(fixedRate = 10000) @Async public void asyncTask() { // 异步执行 } - 幂等设计:任务应支持重复执行不产生副作用
6.2 监控与日志
@Scheduled(fixedRate = 30000)
public void monitoredTask() {
long start = System.currentTimeMillis();
try {
// 业务逻辑
logger.info("任务执行成功,耗时{}ms", System.currentTimeMillis()-start);
} catch (Exception e) {
logger.error("任务执行失败", e);
metrics.counter("task.failure").increment();
}
}
七、常见问题解决方案
7.1 任务不执行排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无任何日志 | 未加@EnableScheduling | 检查启动类注解 |
| 方法未调用 | 类未被Spring管理 | 添加@Component |
| 配置不生效 | cron表达式错误 | 使用在线校验工具 |
7.2 多任务串行问题
// 配置多个线程池
@Bean
public TaskScheduler taskScheduler1() {
return new ThreadPoolTaskScheduler() {{
setPoolSize(3);
setThreadNamePrefix("scheduler1-");
}};
}
@Bean
public TaskScheduler taskScheduler2() {
return new ThreadPoolTaskScheduler() {{
setPoolSize(2);
setThreadNamePrefix("scheduler2-");
}};
}
// 指定调度器
@Scheduled(fixedRate = 1000, scheduler = "taskScheduler1")
public void task1() {}
@Scheduled(fixedRate = 2000, scheduler = "taskScheduler2")
public void task2() {}
八、企业级应用方案
8.1 分布式定时任务
在集群环境中,使用分布式锁确保任务只执行一次:
@Scheduled(cron = "0 0/5 * * * ?")
public void distributedTask() {
if (lock.tryLock()) {
try {
// 获得锁的节点执行任务
} finally {
lock.unlock();
}
}
}
8.2 动态调整策略
@RestController
public class TaskController {
@Autowired
private ScheduledTaskRegistrar registrar;
@PostMapping("/schedule")
public String changeSchedule(@RequestParam long interval) {
registrar.destroy(); // 清除现有任务
registrar.addFixedRateTask(() ->
System.out.println("动态任务"), interval);
return "调度策略已更新";
}
}
九、完整配置示例
9.1 综合配置类
@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {
@Value("${thread.pool.size:5}")
private int poolSize;
@Override
public void configureTasks(ScheduledTaskRegistrar registrar) {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(poolSize);
scheduler.setThreadNamePrefix("scheduled-task-");
scheduler.setErrorHandler(t ->
logger.error("定时任务执行异常", t));
scheduler.setWaitForTasksToCompleteOnShutdown(true);
scheduler.setAwaitTerminationSeconds(60);
scheduler.initialize();
registrar.setTaskScheduler(scheduler);
}
@Bean
public CustomTask customTask() {
return new CustomTask();
}
}
@Component
class CustomTask {
private static final Logger logger = LoggerFactory.getLogger(CustomTask.class);
@Scheduled(cron = "${task.cron.expression}")
public void execute() {
logger.info("自定义任务执行中...");
// 业务逻辑
}
}
9.2 生产级任务模板
public abstract class AbstractScheduledTask {
protected final Logger logger = LoggerFactory.getLogger(getClass());
public final void run() {
String taskName = getClass().getSimpleName();
long start = System.currentTimeMillis();
try {
logger.info("任务[{}]开始执行", taskName);
doExecute();
logger.info("任务[{}]执行成功,耗时{}ms",
taskName, System.currentTimeMillis()-start);
} catch (Exception e) {
logger.error("任务[{}]执行失败", taskName, e);
// 告警通知
}
}
protected abstract void doExecute();
}
@Component
class PaymentCheckTask extends AbstractScheduledTask {
@Scheduled(cron = "0 0 9,15 * * ?")
@Override
protected void doExecute() {
// 具体的对账逻辑
}
}
通过以上方案,可以构建出健壮、可维护的定时任务系统。关键点总结:
- 合理设置线程池大小避免资源竞争
- 所有任务必须实现异常处理
- 生产环境建议添加任务执行监控
- 分布式环境需要协调任务执行
- 复杂任务建议采用模板方法模式
定时任务作为系统核心组件,其稳定性直接影响业务连续性,建议在实施前进行充分的压力测试和故障演练。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END
























暂无评论内容