使用 @EnableScheduling 注解表示打开定时任务,该注解其实是导入了一个 SchedulingConfiguration ( 调度配置 ) 组件。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class) //导入组件
@Documented
public @interface EnableScheduling {}
SchedulingConfiguration -->
组件中配置了一个 ScheduledAnnotationBeanPostProcessor 类型后置处理器。
1、在 Bean 初始化后,对含有 @Scheduled 的方法封装成 CronTask 对象,并添加到定时任务列表中。
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
//对注册的 Bean 进行处理
Object postProcessAfterInitialization(Object bean, String beanName){
//获取Bean中携带了 @Scheduled 注解的方法集合和注解集合
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods();
....
//对获取的集合调用 processScheduled() 函数处理,封装顶定时任务,并添加到列表中.
annotatedMethods.forEach((method, scheduledMethods) ->
scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));
....
}
//处理携带 @Scheduled 注解的方法
void processScheduled(Scheduled scheduled, Method method, Object bean) {
//获取时间表达式
String cron = scheduled.cron();
if (StringUtils.hasText(cron)) {
.......
//添加任务 scheduleCronTask()
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
.....
}
}
2、当所有的bean都初始化完成后,触发事件启动定时任务
void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.applicationContext) {
finishRegistration();
}
}
void finishRegistration() {
.......
//启动任务
this.registrar.afterPropertiesSet();
}
public class ScheduledTaskRegistrar {
@Override
public void afterPropertiesSet() {
scheduleTasks();
}
@SuppressWarnings("deprecation")
protected void scheduleTasks() {
......
if (this.cronTasks != null) {
//对cron表达式的定时任务列表一一启动
for (CronTask task : this.cronTasks) {
addScheduledTask(scheduleCronTask(task));
}
}
......
}
@Nullable
public ScheduledTask scheduleCronTask(CronTask task) {
................
if (this.taskScheduler != null) {
scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());
}
................
}
}
ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
ErrorHandler errorHandler = (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
/*
ReschedulingRunnable.schedule() 启动任务的方式是调用了 scheduledExecutor.schedule() 方法
scheduledExecutor = java.util.concurrent.ScheduledExecutorService
*/
return new ReschedulingRunnable(task, trigger,this.scheduledExecutor,errorHandler).schedule();
}