spring定时任务框架Schelduler源码解析
1.第一步@scheduler的注解bean注册、初始化后置处理器 ScheduledAnnotationBeanPostProcessor
关键点初始化spring容器。
(1).获取带有scheduler注解的方法,并转化为 Map<Method, Set>保存带@Scheduler注解的方法作为key,Scheduled保存的定时器参数作为value。
(2)处理步骤一返回带有@scheduler注解方法的信息集合Map<Method, Set>,然后把任务根据Scheduled信息区分成CronTask(带cron表达式的任务)、FixedDelayTask(带延迟的任务)和FixedRateTask(固定频率的任务)分别添加到ScheduledTaskRegistrar任务处理中心。
(3).任务注册处理中心ScheduledTaskRegistrar,继承了InitializingBean接口,初始化时调用afterPropertiesSet方法完成ConcurrentTaskScheduler初始化taskScheduler,任务归类,传给ConcurrentTaskScheduler处理任务。
(4).任务交给ConcurrentTaskScheduler执行器,并获取future并行处理工具类,ConcurrentTaskScheduler执行器把任务交给ScheduledThreadPoolExecutor延时线程池执行器处理,ScheduledThreadPoolExecutor把任务放入延迟任务队列。
(5).消费任务会调用任务ScheduledFutureTask的run方法,检查是否是周期任务,周期任务并计算下一次任务删除之前的旧任务并重新加入队列。等待消费者消费队列
2.核心代码讲解
ScheduledAnnotationBeanPostProcessor类
初始化spring容器后置处理器ScheduledAnnotationBeanPostProcessor,获取带有scheduler注解的方法,并转化为 Map<Method, Set>保存带@Scheduler注解的方法作为key,Scheduled保存的定时器参数作为value,处理步骤一返回带有@scheduler注解方法的信息集合Map<Method, Set>,然后把任务根据Scheduled信息区分成CronTask(带cron表达式的任务)、FixedDelayTask(带延迟的任务)和FixedRateTask(固定频率的任务)分别添加到ScheduledTaskRegistrar任务注册处理中心。
public Object postProcessAfterInitialization(Object bean, String beanName) {
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
if (!this.nonAnnotatedClasses.contains(targetClass)) {
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, (method) -> {
**//获取带有scheduler注解的方法,并转化为 Map<Method, Set<Scheduled>>保存带@Scheduler注解的方法作为key,Scheduled保存的定时器参数作为value**
Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
return !scheduledMethods.isEmpty() ? scheduledMethods : null;
});
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(targetClass);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No @Scheduled annotations found on bean class: " + bean.getClass());
}
} else {
annotatedMethods.forEach((method, scheduledMethods) -> {
scheduledMethods.forEach((scheduled) -> {
this.processScheduled(scheduled, method, bean); **//如果annotatedMethods不为空则处理带有schduler注解的方法**
});
});
if (this.logger.isDebugEnabled()) {
this.logger.debug(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': " + annotatedMethods);
}
}
}
return bean;
}
**处理带有@schedluer注解的方法**
protected void processScheduled(Scheduled scheduled, Method method, Object bean) {
try {
Assert.isTrue(method.getParameterCount() == 0, "Only no-arg methods may be annotated with @Scheduled");
Method invocableMethod = AopUtils.selectInvocableMethod(method, bean.getClass());
Runnable runnable = new ScheduledMethodRunnable(bean, invocableMethod);
boolean processedSchedule = false;
String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
Set<ScheduledTask> tasks = new LinkedHashSet(4);
long initialDelay = scheduled.initialDelay();
String initialDelayString = scheduled.initialDelayString();
if (StringUtils.hasText(initialDelayString)) {
Assert.isTrue(initialDelay < 0L, "Specify 'initialDelay' or 'initialDelayString', not both");
if (this.embeddedValueResolver != null) {
initialDelayString = this.embeddedValueResolver.resolveStringValue(initialDelayString);
}
if (StringUtils.hasLength(initialDelayString)) {
try {
initialDelay = parseDelayAsLong(initialDelayString);
} catch (RuntimeException var25) {
throw new IllegalArgumentException("Invalid initialDelayString value \"" + initialDelayString + "\" - cannot parse into long");
}
}
}
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 == -1L, "'initialDelay' not supported for cron triggers");
processedSchedule = true;
TimeZone timeZone;
if (StringUtils.hasText(zone)) {
timeZone = StringUtils.parseTimeZoneString(zone);
} else {
timeZone = TimeZone.getDefault();
}
**//向任务注册中心注册CronTask任务**
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
}
}
if (initialDelay < 0L) {
initialDelay = 0L;
}
long fixedDelay = scheduled.fixedDelay();
if (fixedDelay >= 0L) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
**//向任务注册中心注册FixedDelayTask任务**
tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));
}
String fixedDelayString = scheduled.fixedDelayString();
if (StringUtils.hasText(fixedDelayString)) {
if (this.embeddedValueResolver != null) {
fixedDelayString = this.embeddedValueResolver.resolveStringValue(fixedDelayString);
}
if (StringUtils.hasLength(fixedDelayString)) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
try {
fixedDelay = parseDelayAsLong(fixedDelayString);
} catch (RuntimeException var24) {
throw new IllegalArgumentException("Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into long");
}
tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));**//向任务注册中心注册FixedDelayTask任务**
}
}
long fixedRate = scheduled.fixedRate();
if (fixedRate >= 0L) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
**//向任务注册中心注册FixedRateTask任务**
tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
}
String fixedRateString = scheduled.fixedRateString();
if (StringUtils.hasText(fixedRateString)) {
if (this.embeddedValueResolver != null) {
fixedRateString = this.embeddedValueResolver.resolveStringValue(fixedRateString);
}
if (StringUtils.hasLength(fixedRateString)) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
try {
fixedRate = parseDelayAsLong(fixedRateString);
} catch (RuntimeException var23) {
throw new IllegalArgumentException("Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into long");
}
tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
}
}
Assert.isTrue(processedSchedule, errorMessage);
Map var19 = this.scheduledTasks;
synchronized(this.scheduledTasks) {
Set<ScheduledTask> registeredTasks = (Set)this.scheduledTasks.get(bean);
if (registeredTasks == null) {
registeredTasks = new LinkedHashSet(4);
this.scheduledTasks.put(bean, registeredTasks);
}
((Set)registeredTasks).addAll(tasks);
}
} catch (IllegalArgumentException var26) {
throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + var26.getMessage());
}
}
ScheduledTaskRegistrar任务处理中心
任务注册处理中心ScheduledTaskRegistrar,继承了InitializingBean接口,初始化时调用afterPropertiesSet方法完成ConcurrentTaskScheduler初始化taskScheduler,任务归类,传给ConcurrentTaskScheduler处理任务。
public void afterPropertiesSet() {
this.scheduleTasks(); //初始化任务执行器,并添加任务且执行调度
}
protected void scheduleTasks() {
if (this.taskScheduler == null) {
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
Iterator var1;
if (this.triggerTasks != null) {
var1 = this.triggerTasks.iterator();
while(var1.hasNext()) {
TriggerTask task = (TriggerTask)var1.next();
this.addScheduledTask(this.scheduleTriggerTask(task));
}
}
if (this.cronTasks != null) {
var1 = this.cronTasks.iterator();
while(var1.hasNext()) {
CronTask task = (CronTask)var1.next();
this.addScheduledTask(this.scheduleCronTask(task));
}
}
IntervalTask task;
if (this.fixedRateTasks != null) {
var1 = this.fixedRateTasks.iterator();
while(var1.hasNext()) {
task = (IntervalTask)var1.next();
this.addScheduledTask(this.scheduleFixedRateTask(task));
}
}
if (this.fixedDelayTasks != null) {
var1 = this.fixedDelayTasks.iterator();
while(var1.hasNext()) {
task = (IntervalTask)var1.next();
this.addScheduledTask(this.scheduleFixedDelayTask(task));
}
}
}
@Nullable
public ScheduledTask scheduleFixedRateTask(FixedRateTask task) {
ScheduledTask scheduledTask = (ScheduledTask)this.unresolvedTasks.remove(task);
boolean newTask = false;
if (scheduledTask == null) {
scheduledTask = new ScheduledTask(task);
newTask = true;
}
if (this.taskScheduler != null) {
if (task.getInitialDelay() > 0L) {
Date startTime = new Date(System.currentTimeMillis() + task.getInitialDelay());
**//任务交给ConcurrentTaskScheduler执行器并过去future并行处理工具类**
scheduledTask.future = this.taskScheduler.scheduleAtFixedRate(task.getRunnable(), startTime, task.getInterval());
} else {
***//任务交给ConcurrentTaskScheduler执行器并过去future并行处理工具类*
scheduledTask.future = this.taskScheduler.scheduleAtFixedRate(task.getRunnable(), task.getInterval());
}
} else {
this.addFixedRateTask(task);
this.unresolvedTasks.put(task, scheduledTask);
}
return newTask ? scheduledTask : null;
}
ConcurrentTaskScheduler并行任务执行器执行任务
任务交给ConcurrentTaskScheduler执行器并过去future并行处理工具类,ConcurrentTaskScheduler执行器把任务交给ScheduledThreadPoolExecutor延时线程池执行器处理,ScheduledThreadPoolExecutor把任务放入延迟任务队列。
ConcurrentTaskScheduler并行任务执行器执行任务
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
long initialDelay = startTime.getTime() - System.currentTimeMillis();
try {
**//交给ScheduledThreadPoolExecutor延时线程池执行器处理**
return this.scheduledExecutor.scheduleAtFixedRate(this.decorateTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException var8) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, var8);
}
}
**ScheduledThreadPoolExecutor类处理FixedRatTask任务放任务到延迟队列**
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
if (period <= 0)
throw new IllegalArgumentException();
**//转化成ScheduledFutureTask(盛放任务的延迟队列,和下一次任务信息)**
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t; //获取下一次任务
delayedExecute(t); //执行下一次任务
return t;
}
ScheduledFutureTask任务对象
消费任务会调用任务ScheduledFutureTask的run方法,检查是否是周期任务,周期任务并计算下一次任务删除之前的旧任务并重新加入队列。等待消费者消费队列。
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
ScheduledFutureTask.super.run(); //不是周期性任务
else if (ScheduledFutureTask.super.runAndReset()) { //周期性任务
setNextRunTime(); //设置下一次任务事件
reExecutePeriodic(outerTask); // 删除延时任务,并把新任务放入延迟队列中
}
}
/**
* Requeues a periodic task unless current run state precludes it.
* Same idea as delayedExecute except drops task rather than rejecting.
*
* @param task the task
*/
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
if (canRunInCurrentRunState(true)) {
super.getQueue().add(task);
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
ensurePrestart();
}
}
作者相关文章:
JAVA中的CAS和ABA问题