spring的Schedule定时任务执行源码分析

版本说明

  • 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实现定时调度核心的类

其中有三个方法会在启动的时候就调用,他们分别是:

  1. postProcessAfterInitialization
  2. onApplicationEvent
  3. 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));
			}
		}
	}

冲,冲,冲

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值