【Springboot知识】Springboot计划任务Schedule详解
文章目录
- Spring Boot 定时任务从原理到实现详解
- 一、核心原理分析
- 1. 架构分层
- 2. 核心组件
- 3. 线程模型
- 二、基础实现步骤
- 1. 添加依赖
- 2. 主类配置
- 3. 定时任务类
- 三、高级配置技巧
- 1. 自定义线程池
- 2. 动态配置参数
- 3. 分布式锁集成(Redis示例)
- 四、异常处理机制
- 1. 统一异常处理器
- 2. 任务重试机制
- 五、监控与调试
- 1. Actuator 端点
- 2. 性能监控
- 六、完整示例项目结构
- 七、最佳实践建议
- Schedule注解参数详细说明
- 一、注解基础参数详解
- 1. 核心参数配置
- 2. 参数对照表
- 二、Cron表达式详解
- 1. 标准格式
- 2. 特殊字符说明
- 3. 常用表达式示例
- 三、多模式配置示例
- 1. 基础模式组合
- 2. 动态参数注入
- 四、高级使用技巧
- 1. 多任务并行执行
- 2. 条件化调度
- 3. 分布式锁集成
- 五、异常处理机制
- 1. 自定义异常处理器
- 2. 重试机制
- 六、常见问题解决方案
- 1. 任务不执行排查
- 2. 多实例重复执行
- 七、最佳实践建议
Spring Boot 定时任务从原理到实现详解
一、核心原理分析
1. 架构分层
graph TDA[Application] --> B[@EnableScheduling]B --> C[ScheduledAnnotationBeanPostProcessor]C --> D[TaskScheduler]D --> E[ThreadPoolTaskScheduler]D --> F[ConcurrentTaskScheduler]
2. 核心组件
- @EnableScheduling:启用定时任务自动配置
- ScheduledAnnotationBeanPostProcessor:解析@Scheduled注解
- TaskScheduler:任务调度接口
- CronTrigger:处理cron表达式
3. 线程模型
// 默认线程池配置
public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupportimplements TaskScheduler, SchedulingTaskExecutor {private volatile int poolSize = 1; // 默认单线程private ThreadFactory threadFactory = new CustomizableThreadFactory("task-scheduler-");
}
二、基础实现步骤
1. 添加依赖
<!-- pom.xml -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency>
2. 主类配置
@SpringBootApplication
@EnableScheduling
public class SchedulingApplication {public static void main(String[] args) {SpringApplication.run(SchedulingApplication.class, args);}
}
3. 定时任务类
@Component
public class ScheduledTasks {private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);// 固定频率(任务开始时间间隔)@Scheduled(fixedRate = 5000)public void fixedRateTask() {log.info("Fixed Rate Task :: Execution Time - {}", LocalDateTime.now());}// 固定延迟(任务结束时间间隔)@Scheduled(fixedDelay = 7000, initialDelay = 2000)public void fixedDelayTask() {log.info("Fixed Delay Task :: Execution Time - {}", LocalDateTime.now());}// Cron表达式@Scheduled(cron = "0 0/15 9-17 * * MON-FRI")public void cronTask() {log.info("Cron Task :: Execution Time - {}", LocalDateTime.now());}
}
三、高级配置技巧
1. 自定义线程池
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();taskScheduler.setPoolSize(5);taskScheduler.setThreadNamePrefix("custom-scheduler-");taskScheduler.initialize();taskRegistrar.setTaskScheduler(taskScheduler);}
}
2. 动态配置参数
application.properties
schedule.rate=10000
schedule.delay=5000
schedule.cron=0 0 8 * * *
@Scheduled(fixedRateString = "${schedule.rate}")
public void dynamicRateTask() {// ...
}@Scheduled(cron = "${schedule.cron}")
public void dynamicCronTask() {// ...
}
3. 分布式锁集成(Redis示例)
@Scheduled(fixedRate = 10000)
public void distributedTask() {String lockKey = "scheduledTaskLock";String requestId = UUID.randomUUID().toString();try {if (redisLockUtil.tryGetLock(lockKey, requestId, 30)) {log.info("Acquired lock, executing task...");// 业务逻辑}} finally {redisLockUtil.releaseLock(lockKey, requestId);}
}
四、异常处理机制
1. 统一异常处理器
@ControllerAdvice
public class SchedulingExceptionHandler {@ExceptionHandler(TaskExecutionException.class)public void handleTaskException(TaskExecutionException ex) {log.error("Scheduled task failed: {}", ex.getMessage());// 发送告警通知}
}
2. 任务重试机制
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
@Scheduled(fixedRate = 5000)
public void retryableTask() {// 可能失败的业务逻辑if (Math.random() > 0.5) {throw new RuntimeException("Simulated error");}
}
五、监控与调试
1. Actuator 端点
management.endpoints.web.exposure.include=scheduledtasks
访问 /actuator/scheduledtasks
查看任务列表:
{"cron": [{"runnable": {"target": "com.example.ScheduledTasks.cronTask"},"expression": "0 0/15 9-17 * * MON-FRI"}]
}
2. 性能监控
@Scheduled(fixedRate = 5000)
@Timed(value = "scheduled.task", description = "监控任务执行时间")
public void monitoredTask() {// 业务逻辑
}
六、完整示例项目结构
scheduling-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/
│ │ │ ├── config/
│ │ │ │ └── SchedulerConfig.java
│ │ │ ├── ScheduledTasks.java
│ │ │ └── SchedulingApplication.java
│ │ └── resources/
│ │ ├── application.properties
│ │ └── logback-spring.xml
│ └── test/
└── pom.xml
七、最佳实践建议
-
线程池配置原则:
# 推荐线程数 = CPU核心数 * 2(IO密集型) # 推荐线程数 = CPU核心数 + 1(计算密集型)
-
任务设计规范:
- 单任务执行时间 < 调度间隔时间
- 添加事务边界控制
- 避免任务间状态共享
-
生产环境注意事项:
// 添加健康检查 @Component public class ScheduleHealthIndicator implements HealthIndicator {@Overridepublic Health health() {// 检查任务最后执行时间return Health.up().build();} }
通过以上配置和实现,可以构建出高可靠、易维护的定时任务系统。定时任务的执行频率需要根据实际业务需求进行合理设置,同时要特别注意在分布式环境下的任务协调问题。
Schedule注解参数详细说明
一、注解基础参数详解
1. 核心参数配置
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {String cron() default "";String zone() default "";long fixedDelay() default -1;String fixedDelayString() default "";long fixedRate() default -1;String fixedRateString() default "";long initialDelay() default -1;String initialDelayString() default "";
}
2. 参数对照表
参数名称 | 类型 | 必填 | 默认值 | 说明 |
---|---|---|---|---|
cron | String | 否 | “” | Unix风格的cron表达式 |
zone | String | 否 | “” | 时区ID(如"Asia/Shanghai") |
fixedDelay | long | 否 | -1 | 上次执行结束到下次执行的间隔(毫秒) |
fixedDelayString | String | 否 | “” | 支持占位符的字符串形式(如"${schedule.delay}") |
fixedRate | long | 否 | -1 | 固定频率执行(毫秒) |
fixedRateString | String | 否 | “” | 支持占位符的字符串形式 |
initialDelay | long | 否 | -1 | 首次执行的延迟时间(毫秒) |
initialDelayString | String | 否 | “” | 支持占位符的字符串形式 |
二、Cron表达式详解
1. 标准格式
秒(0-59) 分(0-59) 时(0-23) 日(1-31) 月(1-12) 周(0-7) 年(可选)
2. 特殊字符说明
字符 | 含义 | 示例 | 说明 |
---|---|---|---|
* | 任意值 | 0 * * * * * | 每分钟0秒执行 |
? | 不指定(仅日/周字段) | 0 0 0 ? * MON | 每周一0点执行 |
- | 范围 | 0 0 9-17 * * * | 每天9点到17点整点执行 |
, | 多个值 | 0 0 8,12,18 * * * | 每天8、12、18点执行 |
/ | 间隔频率 | 0 0/15 * * * * | 每15分钟执行一次 |
L | 最后一天/最后一周 | 0 0 0 L * ? | 每月最后一天0点执行 |
W | 最近工作日 | 0 0 0 LW * ? | 每月最后一个工作日执行 |
# | 第几个周几 | 0 0 0 ? * 5#2 | 每月第2个周四执行 |
3. 常用表达式示例
@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
@Scheduled(cron = "0 0/5 9-17 * * MON-FRI") // 工作日9-17点每5分钟执行
@Scheduled(cron = "0 0 12 1 * ?") // 每月1号中午12点执行
@Scheduled(cron = "0 0 8 L * ?") // 每月最后一天上午8点执行
三、多模式配置示例
1. 基础模式组合
// 初始延迟3秒,之后每5秒执行
@Scheduled(initialDelay = 3000, fixedRate = 5000) // 每天8:30执行(使用属性配置)
@Scheduled(cron = "${app.schedule.daily-report}")
2. 动态参数注入
application.properties
schedule.interval=5000
schedule.initial.delay=10000
schedule.cron.expression=0 0/15 * * * *
@Scheduled(fixedRateString = "${schedule.interval}",initialDelayString = "${schedule.initial.delay}"
)
public void dynamicScheduleTask() {// 业务逻辑
}@Scheduled(cron = "${schedule.cron.expression}")
public void cronTask() {// 定时任务
}
四、高级使用技巧
1. 多任务并行执行
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(5);scheduler.setThreadNamePrefix("schedule-pool-");scheduler.initialize();taskRegistrar.setTaskScheduler(scheduler);}
}
2. 条件化调度
@Profile("production") // 仅生产环境生效
@ConditionalOnProperty(name = "scheduler.enabled", havingValue = "true")
@Scheduled(fixedRate = 10000)
public void conditionalTask() {// 生产环境专用任务
}
3. 分布式锁集成
@Scheduled(cron = "0 0/30 * * * ?")
public void distributedTask() {String lockKey = "reportGenerationLock";try {if (redisLock.tryLock(lockKey, 300)) { // 获取30秒锁generateReport();}} finally {redisLock.release(lockKey);}
}
五、异常处理机制
1. 自定义异常处理器
@ControllerAdvice
public class ScheduleExceptionHandler {@ExceptionHandler(ScheduleExecutionException.class)public void handleScheduleException(ScheduleExecutionException ex) {log.error("定时任务执行失败: {}", ex.getMessage());// 发送告警通知alertService.sendAlert("Schedule Failure", ex.getMessage());}
}
2. 重试机制
@Retryable(value = {DataAccessException.class},maxAttempts = 3,backoff = @Backoff(delay = 1000, multiplier = 2)
)
@Scheduled(fixedDelay = 5000)
public void retryableTask() {// 可能失败的数据操作databaseService.batchUpdate();
}
六、常见问题解决方案
1. 任务不执行排查
1. 检查主类是否添加`@EnableScheduling`
2. 确认任务方法为`public`修饰
3. 验证cron表达式有效性(可用在线验证工具)
4. 检查线程池是否被占满(默认单线程)
2. 多实例重复执行
// 使用数据库锁方案示例
@Transactional
@Scheduled(cron = "0 0 3 * * ?")
public void exclusiveTask() {LocalDateTime now = LocalDateTime.now();ScheduleLock lock = lockRepo.findByTaskName("dailyCleanup");if (lock == null || lock.getLockUntil().isBefore(now)) {// 获取锁(设置30分钟有效期)lockRepo.save(new ScheduleLock("dailyCleanup", now.plusMinutes(30)));// 执行任务dataCleanupService.cleanup();// 释放锁lockRepo.deleteById("dailyCleanup");}
}
七、最佳实践建议
-
线程池配置原则
# 推荐配置公式 IO密集型任务:线程数 = CPU核心数 * 2 计算密集型任务:线程数 = CPU核心数 + 1
-
执行时间监控
@Scheduled(fixedRate = 60000) public void monitoredTask() {StopWatch watch = new StopWatch();try {watch.start();// 业务逻辑} finally {watch.stop();if (watch.getTotalTimeMillis() > 5000) {log.warn("任务执行超时: {}ms", watch.getTotalTimeMillis());}} }
-
重要任务日志规范
@Scheduled(cron = "0 0 2 * * ?") public void criticalTask() {log.info("==== 开始执行数据归档任务 ====");try {archiveService.archiveData();log.info("数据归档成功,归档数量: {}", count);} catch (Exception e) {log.error("数据归档失败", e);throw e;} finally {log.info("==== 结束数据归档任务 ====");} }
通过合理配置和遵循最佳实践,可以构建出高可靠、易维护的定时任务系统。特别注意在分布式环境下做好任务协调,避免重复执行导致的数据不一致问题。