Skip to content

Latest commit

 

History

History
315 lines (277 loc) · 12.2 KB

Spring-Scheduling.md

File metadata and controls

315 lines (277 loc) · 12.2 KB

Spring 定时任务

EnableScheduling

  • 首先关注的类为启动定时任务的注解@EnableScheduling
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documentedpublic @interface EnableScheduling { }

SchedulingConfiguration

  • 注册定时任务相关信息
@Configuration@Role(BeanDefinition.ROLE_INFRASTRUCTURE) publicclassSchedulingConfiguration { /** * 开启定时任务 * @return */@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) publicScheduledAnnotationBeanPostProcessorscheduledAnnotationProcessor() { // 注册 ScheduledAnnotationBeanPostProcessorreturnnewScheduledAnnotationBeanPostProcessor(); } }

ScheduledAnnotationBeanPostProcessor

  • 关注 application 事件,以及 spring 生命周期相关的接口实现
/** * application 事件 * @param event the event to respond to */@OverridepublicvoidonApplicationEvent(ContextRefreshedEventevent) { if (event.getApplicationContext() == this.applicationContext) { // Running in an ApplicationContext -> register tasks this late...// giving other ContextRefreshedEvent listeners a chance to perform// their work at the same time (e.g. Spring Batch's job registration).// 注册定时任务finishRegistration(); } }
@OverridepublicObjectpostProcessAfterInitialization(Objectbean, StringbeanName) { if (beaninstanceofAopInfrastructureBean || beaninstanceofTaskScheduler || beaninstanceofScheduledExecutorService) { // Ignore AOP infrastructure such as scoped proxies.returnbean; } // 当前类Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean); if (!this.nonAnnotatedClasses.contains(targetClass)) { // 方法扫描,存在 Scheduled、Schedules 注解的全部扫描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); }); if (annotatedMethods.isEmpty()) { this.nonAnnotatedClasses.add(targetClass); if (logger.isTraceEnabled()) { logger.trace("No @Scheduled annotations found on bean class: " + targetClass); } } else { // Non-empty set of methodsannotatedMethods.forEach((method, scheduledMethods) -> // 处理 scheduled 相关信息scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean))); if (logger.isTraceEnabled()) { logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': " + annotatedMethods); } } } returnbean; }
  • 处理定时任务注解
protectedvoidprocessScheduled(Scheduledscheduled, Methodmethod, Objectbean) { try { Runnablerunnable = createRunnable(bean, method); booleanprocessedSchedule = false; StringerrorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required"; Set<ScheduledTask> tasks = newLinkedHashSet<>(4); // Determine initial delay// 是否延迟执行longinitialDelay = scheduled.initialDelay(); // 延迟执行时间StringinitialDelayString = scheduled.initialDelayString(); // 是否有延迟执行的时间if (StringUtils.hasText(initialDelayString)) { Assert.isTrue(initialDelay < 0, "Specify 'initialDelay' or 'initialDelayString', not both"); if (this.embeddedValueResolver != null) { initialDelayString = this.embeddedValueResolver.resolveStringValue(initialDelayString); } if (StringUtils.hasLength(initialDelayString)) { try { initialDelay = parseDelayAsLong(initialDelayString); } catch (RuntimeExceptionex) { thrownewIllegalArgumentException( "Invalid initialDelayString value \"" + initialDelayString + "\" - cannot parse into long"); } } } // Check cron expression// 获取cron表达式Stringcron = scheduled.cron(); // cron表达式是否存在if (StringUtils.hasText(cron)) { // 获取时区Stringzone = scheduled.zone(); if (this.embeddedValueResolver != null) { // 字符串转换cron = this.embeddedValueResolver.resolveStringValue(cron); zone = this.embeddedValueResolver.resolveStringValue(zone); } if (StringUtils.hasLength(cron)) { // cron 是否延迟Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers"); processedSchedule = true; if (!Scheduled.CRON_DISABLED.equals(cron)) { TimeZonetimeZone; if (StringUtils.hasText(zone)) { // 时区解析timeZone = StringUtils.parseTimeZoneString(zone); } else { // 默认时区获取timeZone = TimeZone.getDefault(); } // 创建任务tasks.add(this.registrar.scheduleCronTask(newCronTask(runnable, newCronTrigger(cron, timeZone)))); } } } // At this point we don't need to differentiate between initial delay set or not anymoreif (initialDelay < 0) { initialDelay = 0; } // Check fixed delay// 获取间隔调用时间longfixedDelay = scheduled.fixedDelay(); // 间隔时间>0if (fixedDelay >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; // 创建任务,间隔时间定时任务tasks.add(this.registrar.scheduleFixedDelayTask(newFixedDelayTask(runnable, fixedDelay, initialDelay))); } // 延迟时间StringfixedDelayString = 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 (RuntimeExceptionex) { thrownewIllegalArgumentException( "Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into long"); } // 创建延迟时间任务tasks.add(this.registrar.scheduleFixedDelayTask(newFixedDelayTask(runnable, fixedDelay, initialDelay))); } } // Check fixed rate// 获取调用频率longfixedRate = scheduled.fixedRate(); if (fixedRate >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; // 创建调用频率的定时任务tasks.add(this.registrar.scheduleFixedRateTask(newFixedRateTask(runnable, fixedRate, initialDelay))); } StringfixedRateString = 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 (RuntimeExceptionex) { thrownewIllegalArgumentException( "Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into long"); } tasks.add(this.registrar.scheduleFixedRateTask(newFixedRateTask(runnable, fixedRate, initialDelay))); } } // Check whether we had any attribute setAssert.isTrue(processedSchedule, errorMessage); // Finally register the scheduled taskssynchronized (this.scheduledTasks) { // 定时任务注册Set<ScheduledTask> regTasks = this.scheduledTasks.computeIfAbsent(bean, key -> newLinkedHashSet<>(4)); regTasks.addAll(tasks); } } catch (IllegalArgumentExceptionex) { thrownewIllegalStateException( "Encountered invalid @Scheduled method '" + method.getName() + "': " + ex.getMessage()); } }

定时任务

  • CronTask
    • cron 定时任务
  • FixedDelayTask
    • 间隔时间的定时任务
  • FixedRateTask
    • 调用频率的定时任务
  • ScheduledTask
    • 定时任务对象

cron 表达式解析

  • org.springframework.scheduling.support.CronSequenceGenerator.doParse
privatevoiddoParse(String[] fields) { setNumberHits(this.seconds, fields[0], 0, 60); setNumberHits(this.minutes, fields[1], 0, 60); setNumberHits(this.hours, fields[2], 0, 24); setDaysOfMonth(this.daysOfMonth, fields[3]); setMonths(this.months, fields[4]); setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8); if (this.daysOfWeek.get(7)) { // Sunday can be represented as 0 or 7this.daysOfWeek.set(0); this.daysOfWeek.clear(7); } }

执行定时任务

  • 这里以 CronTask 任务进行分析,其他定时任务同理
    • org.springframework.scheduling.config.ScheduledTaskRegistrar.scheduleCronTask
@NullablepublicScheduledTaskscheduleCronTask(CronTasktask) { // 从未执行的任务列表中删除,并且获取这个任务ScheduledTaskscheduledTask = this.unresolvedTasks.remove(task); booleannewTask = false; // 没有这个任务if (scheduledTask == null) { scheduledTask = newScheduledTask(task); newTask = true; } // 任务调度器是否为空if (this.taskScheduler != null) { scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger()); } else { // 添加到cron任务列表addCronTask(task); // 保存到没有执行的任务中this.unresolvedTasks.put(task, scheduledTask); } return (newTask ? scheduledTask : null); }
close