【小家Spring】Spring任务调度核心接口(类)之---TaskScheduler(任务调度器)、Trigger(触发器)、ScheduledTask(调度任务)详解(上)

简介: 【小家Spring】Spring任务调度核心接口(类)之---TaskScheduler(任务调度器)、Trigger(触发器)、ScheduledTask(调度任务)详解(上)

前言


先推荐阅读此篇:

【小家java】Java定时任务ScheduledThreadPoolExecutor详解以及与Timer、TimerTask的区别(执行指定次数停止任务)


某些时候我们可能需要在某些固定的时间或者是间隔一定的时间连续执行一些任务,如每天凌晨自动跑一些批次/心跳检测等。Spring通过使用TaskScheduler来完成这些功能。


任务调度框架设计到几个核心的接口,下面做如下介绍。


任务调度和JDK的定时器、线程池有关,推荐先阅读上面的{相关阅读}


TriggerContext


该接口表示触发的上下文。它能够获取上次任务原本的计划时间/实际的执行时间以及实际的完成时间

//@since 3.0 我们发现每个方法都有可能返回null(比如首次执行)
public interface TriggerContext {
  // 上次预计的执行时间
  @Nullable
  Date lastScheduledExecutionTime();
  // 上次真正执行时间
  @Nullable
  Date lastActualExecutionTime();
  // 上次完成的时间
  @Nullable
  Date lastCompletionTime();
}


它的唯一实现类:SimpleTriggerContext,源码就不用看了,没有任何逻辑,只有一些赋值操作。


Trigger



TaskScheduler中将会使用到Trigger对象,所以先对它进行分析

Trigger接口用于计算任务的下次执行时间。它的接口定义如下:


public interface Trigger {
  //获取下次执行时间
  @Nullable
  Date nextExecutionTime(TriggerContext triggerContext);
}


image.png


它有如上的两个实现类。


CronTrigger


顾名思义,它通过Cron表达式来生成调度计划。比如:


scheduler.schedule(task, new CronTrigger("0 15 9-17 * * MON-FRI"));

以上表达式表示在工作日的9-17点之间,每隔15分钟执行一次;


Spring对cron表达式的支持,是由CronSequenceGenerator来实现的,不依赖于别的框架。下面给出一个Demo感受下:

    public static void main(String[] args) {
        CronSequenceGenerator generator = new CronSequenceGenerator("0 15 * * * MON-FRI");
        Date next = generator.next(new Date());
        System.out.println(next); //Mon Apr 22 17:15:00 CST 2019
        System.out.println(generator.next(next)); //Mon Apr 22 18:15:00 CST 2019
    }


这个类若我们自己需要解析Cron表达式,也是可以拿出来使用的。

CronTrigger的原理也比较简单,主要是实现了nextExecutionTime方法:


  @Override
  public Date nextExecutionTime(TriggerContext triggerContext) {
    Date date = triggerContext.lastCompletionTime();
    // 这里面有个处理:如果data为null,相当于任务已经完成了
    if (date != null) {
      // 拿到上一次预定执行的时间
      Date scheduled = triggerContext.lastScheduledExecutionTime();
      // 如果预定执行的时间为null(比如第一次)或者上一次还在data之后,那就取当前时间嘛
      if (scheduled != null && date.before(scheduled)) {
        // Previous task apparently executed too early...
        // Let's simply use the last calculated execution time then,
        // in order to prevent accidental re-fires in the same second.
        date = scheduled;
      }
    }
    // 如果任务还没有完成,那就以当前时间去计算下一个时间
    else {
      date = new Date();
    }
    return this.sequenceGenerator.next(date);
  }


PeriodicTrigger


用于定期执行的Trigger;它有两种模式:


  • fixedRate:两次任务开始时间之间间隔指定时长
  • fixedDelay: 上一次任务的结束时间与下一次任务开始时间``间隔指定时长


可见这两种情况的区别就在于,在决定下一次的执行计划时是否要考虑上次任务在什么时间执行完成。 默认情况下PeriodicTrigger使用了fixedDelay模式。


  • period: long类型,表示间隔时长,注意在fixedRate与fixedDelay两种模式下的不同含义
  • timeUnit: TimeUnit类型,表示间隔时长的单位,如毫秒等;默认是毫秒
  • initialDelay: long类型,表示启动任务后间隔多长时间开始执行第一次任务
  • fixedRate: boolean类型,表示是否是fixedRate,为True时是fixedRate,否则是fixedDelay,默认为False



TaskScheduler


Spring任务调度器的核心接口,定义了执行定时任务的主要方法,主要根据任务的不同触发方式调用不同的执行逻辑,其实现类都是对JDK原生的定时器或线程池组件进行包装,并扩展额外的功能。


TaskScheduler用于对Runnable的任务进行调度,它包含有多种触发规则。


public interface TaskScheduler {
  // 提交任务调度请求 
  // Runnable task:待执行得任务
  // Trigger trigger:使用Trigger指定任务调度规则
  @Nullable
  ScheduledFuture<?> schedule(Runnable task, Trigger trigger);
  // @since 5.0  这里使用的Instant 类,其实最终也是转换成了Date
  default ScheduledFuture<?> schedule(Runnable task, Instant startTime) {
    return schedule(task, Date.from(startTime));
  }
  //  提交任务调度请求   startTime表示它的执行时间
  //  注意任务只执行一次,使用startTime指定其启动时间  
  ScheduledFuture<?> schedule(Runnable task, Date startTime);
  // @since 5.0
  default ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period) {
    return scheduleAtFixedRate(task, Date.from(startTime), period.toMillis());
  }
  // 使用fixedRate的方式提交任务调度请求    任务首次启动时间由传入参数指定 
  // task 待执行的任务  startTime 任务启动时间    period 两次任务启动时间之间的间隔时间,默认单位是毫秒
  ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period);
  // @since 5.0
  default ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period) {
    return scheduleAtFixedRate(task, period.toMillis());
  }
  // 使用fixedRate的方式提交任务调度请求 任务首次启动时间未设置,任务池将会尽可能早的启动任务
  // task 待执行任务 
  // period 两次任务启动时间之间的间隔时间,默认单位是毫秒
  ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period);
  // @since 5.0
  default ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay) {
    return scheduleWithFixedDelay(task, Date.from(startTime), delay.toMillis());
  }
  //  使用fixedDelay的方式提交任务调度请求  任务首次启动时间由传入参数指定 
  // delay 上一次任务结束时间与下一次任务开始时间的间隔时间,单位默认是毫秒 
  ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
  // @since 5.0
  default ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay) {
    return scheduleWithFixedDelay(task, delay.toMillis());
  }
  // 使用fixedDelay的方式提交任务调度请求 任务首次启动时间未设置,任务池将会尽可能早的启动任务 
  // delay 上一次任务结束时间与下一次任务开始时间的间隔时间,单位默认是毫秒 
  ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay);
}


它有如下实现类:


image.png


备注:TaskScheduler的另一实现类TimerManagerTaskScheduler在Spring5.0之后就被直接移除了,因此本处不再讲述

相关文章
|
8月前
|
XML 存储 Java
Spring重要类解析
Spring重要类解析
57 0
|
8月前
|
DataWorks 大数据 API
DataWorks RunTriggerNode接口是只能调度 http触发器节点吗?
DataWorks RunTriggerNode接口是只能调度 http触发器节点吗?
185 1
|
8月前
|
监控 Java 调度
Spring中的任务调度:探索@Scheduled和@Schedules注解的威力
Spring中的任务调度:探索@Scheduled和@Schedules注解的威力
276 0
|
6天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
124 73
|
6天前
|
Java Spring
【Spring配置相关】启动类为Current File,如何更改
问题场景:当我们切换类的界面的时候,重新启动的按钮是灰色的,不能使用,并且只有一个Current File 项目,下面介绍两种方法来解决这个问题。
|
8月前
|
Java 调度 Maven
Spring Task 自定义定时任务类
Spring Task 自定义定时任务类
74 0
|
5月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
60 0
Spring高手之路22——AOP切面类的封装与解析
|
6月前
|
Java Spring
idea新建spring boot 项目右键无package及java类的选项
idea新建spring boot 项目右键无package及java类的选项
249 5
|
6月前
|
Java 数据库连接 API
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
425 1
|
6月前
|
NoSQL Java 调度
在Spring Boot中实现分布式任务调度
在Spring Boot中实现分布式任务调度

热门文章

最新文章