版本说明
- spring 5.2.8.RELEASE
使用
本人为了方便些注释和debug,是在源码中运行的,源码地址
https://gitee.com/LieFengHenNen/spring-source-desc
@EnableScheduling
代码
@Component
public class ScheduledTest {
Integer count = 0;
@Scheduled(fixedRate = 3000, initialDelay = 5000)
public void test1() {
System.out.println("test ====== count "+ ++count);
}
}
只需要进行简单的配置,就可以完成我们以前非常复杂的定时任务,就让我们来探寻它是怎么实现的吧
流程图
入口
分析: @EnableScheduling 这个注解就是入口,开启了这个注解才能使定时任务生效
这个注解导入了类SchedulingConfiguration
接着把这个类 ScheduledAnnotationBeanPostProcessor加入到了spring容器中
ScheduledAnnotationBeanPostProcessor是spring实现定时调度核心的类
其中有三个方法会在启动的时候就调用,他们分别是:
- postProcessAfterInitialization
- onApplicationEvent
- ScheduledTaskRegistrar.afterPropertiesSet
postProcessAfterInitialization
每个bean都会执行这个后置 方法
org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization
收集类上的包含Scheduled注解的方法
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
method, Scheduled.class, Schedules.class);
return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
});
// 找到了有Scheduled 注解的方法集合,进行遍历处理
annotatedMethods.forEach((method, scheduledMethods) ->
scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));
封装成一个类,加入到一个容器中
// Check cron expression
String cron = scheduled.cron();
if (StringUtils.hasText(cron)) {
String zone = scheduled.zone();
if (this.embeddedValueResolver != null) {
cron = this.embeddedValueResolver.resolveStringValue(cron);
zone = this.embeddedValueResolver.resolveStringValue(zone);
}
if (StringUtils.hasLength(cron)) {
Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers");
processedSchedule = true;
if (!Scheduled.CRON_DISABLED.equals(cron)) {
TimeZone timeZone;
if (StringUtils.hasText(zone)) {
timeZone = StringUtils.parseTimeZoneString(zone);
}
else {
timeZone = TimeZone.getDefault();
}
// 注册到registrar的实例中
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
}
}
}
关键的代码 addCronTask(task);
public ScheduledTask scheduleCronTask(CronTask task) {
ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
boolean newTask = false;
if (scheduledTask == null) {
scheduledTask = new ScheduledTask(task);
newTask = true;
}
if (this.taskScheduler != null) {
scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());
}
else {
// 添加到了队列中
addCronTask(task);
this.unresolvedTasks.put(task, scheduledTask);
}
return (newTask ? scheduledTask : null);
}
最终任务加入到这几个成员变量中
this.fixedRateTasks.add(task);
第二个方法onApplicationEvent
finishRegistration();
关键代码就一行
// Search for TaskScheduler bean...
// 从bean工厂查询有没有线程调度池,如果有,设置到注册器中
this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, false));
第三个方法 ScheduledTaskRegistrar.afterPropertiesSet
public void afterPropertiesSet() {
scheduleTasks();
}
第三个方法直接调度任务
protected void scheduleTasks() {
if (this.taskScheduler == null) {
// 这里很关键,模式使用了单线程进行调度,在没有设置任务线程池的情况下
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
if (this.triggerTasks != null) {
for (TriggerTask task : this.triggerTasks) {
addScheduledTask(scheduleTriggerTask(task));
}
}
if (this.cronTasks != null) {
for (CronTask task : this.cronTasks) {
addScheduledTask(scheduleCronTask(task));
}
}
if (this.fixedRateTasks != null) {
for (IntervalTask task : this.fixedRateTasks) {
addScheduledTask(scheduleFixedRateTask(task));
}
}
if (this.fixedDelayTasks != null) {
for (IntervalTask task : this.fixedDelayTasks) {
addScheduledTask(scheduleFixedDelayTask(task));
}
}
}