1.背景
任务调度在很多场景中都需要用到,如延时、周期性执行任务的场景,例如系统没做到闭环时,需要定时去第三方拉取数据然后处理,或者做统计时定时跑统计脚本等等。市面上有很多成熟的调度框架,例如Quartz等,spring本身也提供了简单的调度实现,能够满足常见的任务场景。
2.实现
2.1TaskScheduler接口
Spring的任务调度架构始于接口TaskScheduler,该接口的方法大体上可以分为三类:
(1)schedule及其重载方法,代表任务执行的时间点以及条件;
(2)scheduleAtFixedRate及其重载方法,表示任务周期性的执行;
(3)scheduleWithFixedDelay及其重载方法,表示两个任务执行之间的间隔。
综上,任务调度提供了可延时、周期性的任务执行方式,也就是控制任务什么时候执行,以及怎么执行(执行周期,执行间隔),TaskScheduler接口代码如下:
public interface TaskScheduler {
default Clock getClock() {
return Clock.systemDefaultZone();
}
@Nullable
ScheduledFuture<?> schedule(Runnable task, Trigger trigger);
//...schedule重载方法
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period);
//...scheduleAtFixedRate重载方法
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
//...scheduleWithFixedDelay重载方法
}
2.2接口实现
TaskScheduler接口的实现类图如下:
ThreadPoolTaskScheduler实现了TaskScheduler接口,并将具体的调度任务委托给了java并发包下的ScheduledThreadPoolExecutor。下图为ThreadPoolTaskScheduler中ScheduledExecutorService赋值过程:
private ScheduledExecutorService scheduledExecutor;
@Override
protected ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
/*
具体的创建scheduledExecutor的地方
*/
this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);
if (this.removeOnCancelPolicy) {
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(true);
}
else {
logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
}
}
return this.scheduledExecutor;
}
protected ScheduledExecutorService createExecutor(
int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
ConcurrentTaskScheduler则采用了适配器模式,将ScheduledExecutorService适配成TaskScheduler。和ThreadPoolTaskScheduler不同的是,ConcurrentTaskScheduler的默认ScheduledExecutorService实现是Executors.newSingleThreadScheduledExecutor(),也就是poolsize为1的ScheduledThreadPoolExecutor。
从功能上讲,ConcurrentTaskScheduler和ThreadPoolTaskScheduler并没有什么不同(疑惑)?下面放出一张类的完整类图,从整体上把握类的继承结构以及实现。
2.3模式总结
spring的任务调度采用的是适配器模式,回顾适配器模式,总共有三个角色:
(1)适配者Adaptee
(2)目标接口target
(3)适配器Adapter
这里TaskScheduler就是目标接口,ScheduledExecutorService是适配者,TaskScheduler的实现类ConcurrentTaskScheduler等就是适配器。
3.总结
总体上,spring的任务调度采用了适配器模式,基于java并发包的ScheduledExecutorService适配TaskScheduler接口,从而实现任务调度。