Spring Boot 框架学习笔记(七)整合Quartz调度框架

  • 简介
  • 运行环境
  • 核心概念
  • 任务存储方式
  • 常用API
  • 使用案例
  • 1. 添加依赖
  • 2. 创建任务类实现`Job`接口,或者继承`QuartzJobBean`抽象类
  • 实现`Job`接口
  • 继承`QuartzJobBean`抽象类
  • 较于`Job`接口的优点
  • 3. 创建调度类调度执行
  • 实现`Job`类
  • 继承`QuartzJobBean`类
  • 详细说明
  • Job和JobDetail
  • JobExecutionContext


简介

QuartzOpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务。
Quartz可以与J2EE和J2SE应用程序相结合也可以单独使用。

运行环境

  • 嵌入独立的应用程序
  • 在应用程序服务器(或servlet容器)内被实例化,参与事务
  • 作为一个独立程序运行,可以通过RMI使用
  • 可以作为独立的项目集群被实例化(负载平衡和故障转移功能),用于作业执行

核心概念

  1. 任务Job

需要实现的任务类,每个job都必须实现org.quartz.job接口,实现 execute() 方法,执行后完成任务。

//通过JobBulider构建一个任务实例
JobDetail jobDetail = JobBuilder.newJob(xxxJob.class);
  1. 触发器 Trigger

执行任务的触发器(定时),主要包含SimpleTriggerCronTrigger以及自定义Trigger

//通过TriggerBuilder构建触发器实例
 SimpleTrigger trigger = TriggerBuilder.newTrigger();
  1. 调度器 Scheduler

任务调度器,负责基于 Trigger触发器设定的时间来执行Job任务。

//从调度工厂获取
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

任务存储方式

Quartz提供了两种存储任务的方式:

  • Memory:内存方式,将任务存储到内存中,当项目重启时就会丢失,不建议生产环境使用。
  • Jdbc:数据库方式,将任务存储到Quartz提供的固定结构的表内,项目重启任务不会丢失。

常用API

  • Scheduler:用于定时调度程序交互的主程序接口。

Scheduler调度程序:任务执行计划表,通过scheduler.scheduleJob方法安排进执行任务,当到了预先定义的执行时间的时候触发trigger,执行任务

  • Job:可自定义的在未来某个时间能被调度程序执行的任务类
  • JobDetail:使用JobDetail来定义定时任务的实例,JobDetail实例是通过JobBuilder类创建的
  • JobDataMap:可以包含不限量(序列化的)的数据对象,在Job实例执行的时候,可以使用其中的数据;

JobDataMapJava Map接口的一个实现,额外增加了一些便于存取基本类型数据的方法

  • Trigger:触发器,触发执行Job任务。定义一个已被安排的任务将在什么时候执行的时间条件
  • JobBuilder:用于声明一个任务实例,也可以定义关于该任务的详情比如任务名,组名等。通过JobBuilder声明的实例将会作为一个实际执行的任务。
  • TriggerBuilder:触发器创建器,用于创建触发器trigger实例
  • JobListener、TriggerListener、SchedulerListener:监听器,用于对组件的监听

使用案例

1. 添加依赖

springboot版本2.0之后

<!--quartz依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

springboot版本较低

<!--核心包-->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
 <!--工具包-->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.2</version>
</dependency>

2. 创建任务类实现Job接口,或者继承QuartzJobBean抽象类

实现Job接口

/**
 * 任务类
 * */
public class HelloJob implements Job {
    static int i = 1;
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("第"+i+++"次"+"Hello,Quartz!");
    }
}

继承QuartzJobBean抽象类

/**
 * 任务类
 * */
public class HelloJob extends QuartzJobBean {
    static int i = 1;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("第"+i+++"次"+"Hello,Quartz!");
    }
}

QuartzJobBean是由Spring提供,实现org.quartz.Job接口,是对Quartz内置任务接口的实现封装,源码如下:

public abstract class QuartzJobBean implements Job {
    public QuartzJobBean() {
    }

    public final void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            MutablePropertyValues pvs = new MutablePropertyValues();
            pvs.addPropertyValues(context.getScheduler().getContext());
            pvs.addPropertyValues(context.getMergedJobDataMap());
            bw.setPropertyValues(pvs, true);
        } catch (SchedulerException var4) {
            throw new JobExecutionException(var4);
        }

        this.executeInternal(context);
    }

    protected abstract void executeInternal(JobExecutionContext var1) throws JobExecutionException;
}
较于Job接口的优点
  • 自动将实现类实例加入IOC

使用QuartzJobBean来创建自定义任务时,Spring会自动扫描项目内的实现类,将每一个实现类通过反射机制创建出实例并将实例写入到IOC容器内。

  • 可在实现类内注入实例

直接使用Quartz时,如果自定义任务类实例不加入IOC容器,我们无法在自定义任务类注入Service

3. 创建调度类调度执行

实现Job

/**
 * 调度器
 * */
public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        //1.从调度工厂获取调度器实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //2. 通过JobBulider构建一个任务实例
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                //设置任务的唯一实例名和任务组的组名
                .withIdentity("helloJob","helloGroup")
                //构建实例
                .build();
        //3. 通过TriggerBuilder构建触发器实例
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                //设置触发器唯一实例名和触发器组名
                .withIdentity("helloTrigger","helloGroup")
                //执行计划,每3秒执行一次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
                //立即执行
                .startNow()
                //构建实例
                .build();
        //4. 调度器绑定任务实例和触发器
        scheduler.scheduleJob(jobDetail,trigger);
        //5.开始定时任务
        scheduler.start();
    }

}

Springbatch任务调度面试题 springboot任务调度框架_java

继承QuartzJobBean

  • 创建配置类

详细说明

Job和JobDetail

  • JOB

Job:工作任务调度接口,任务类需要实现的接口。该接口中定义了execute方法,类似JDK提供的TimeTask类的run`方法。在这里面编写任务执行的业务逻辑

Job实例在Quartz中的生命周期:每次调度器执行Job时,它在调用execute方法前会创建一个新的Job实例,当调度完成后,管理的Job对象实例将会被释放,释放的实例会被垃圾回收机制回收

  • JobDetail

JobDetail:作用是绑定 Job,每次Scheduler调度执行一个Job的时候,首先会拿到对应的Job,然后创建该Job实例,再去执行Job中的execute()的内容,任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。除此之外,JobDetail为Job实例提供了许多设置属性

  • 为什么要使用Job+JobDetail模式,而不是直接使用Job

JobDetail定义任务属性,Job定义任务逻辑
任务有可能并发执行,当直接使用Job的时候,Job实例可能出现并发访问的情况。
使用Job+JobDetail模式,每次调度执行都会生成一个Job实例,这样就不用担心并发访问的问题

JobExecutionContext

Scheduler调用一个Job,就会将JobExecutionContext传递给Jobexecute()方法
Job能通过JobExecuteContext对象访问到Quartz运行时的环境以及Job本身的明细数据