Quartz

更多精彩关注掌上编程公众号

一、什么是Quartz


Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,
可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能:

    1. 持久性作业 - 就是保持调度定时的状态;
    2. 作业管理 - 对调度作业进行有效的管理; 

大部分公司都会用到定时任务这个功能。
拿火车票购票来说,当你下单后,后台就会插入一条待支付的task(job),一般是30分钟,超过30min后就会执行这个job,去判断你是否支付,未支付就会取消此次订单;当你支付完成之后,后台拿到支付回调后就会再插入一条待消费的task(job),Job触发日期为火车票上的出发日期,超过这个时间就会执行这个job,判断是否使用等。

在我们实际的项目中,当Job过多的时候,肯定不能人工去操作,这时候就需要一个任务调度框架,帮我们自动去执行这些程序。那么该如何实现这个功能呢?

(1)首先我们需要定义实现一个定时功能的接口,我们可以称之为Task(或Job),如定时发送邮件的task(Job),重启机器的task(Job),优惠券到期发送短信提醒的task(Job),实现接口如下:

(2)有了任务之后,还需要一个能够实现触发任务去执行的触发器,触发器Trigger最基本的功能是指定Job的执行时间,执行间隔,运行次数等。

(3)有了Job和Trigger后,怎么样将两者结合起来呢?即怎样指定Trigger去执行指定的Job呢?这时需要一个Schedule,来负责这个功能的实现。

上面三个部分就是Quartz的基本组成部分:

1. 调度器:Scheduler
2. 任务:JobDetail
3. 触发器:Trigger,包括SimpleTrigger和CronTrigger

二、Quartz Demo搭建

下面来利用Quartz搭建一个最基本的Demo。
1、导入依赖的jar包:


<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

2、新建一个能够打印任意内容的Job:


/**
 * @author 2460798168@qq.com
 * @date 2019/12/3 11:36
 */
public class DemoJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String printTime = new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(new Date());
        System.out.println("PrintWordsJob start at:" + printTime + ", prints: Hello Job-" + new Random().nextInt(100));
    }
}

3、创建Schedule,执行任务:


/**
 * @author 2460798168@qq.com
 * @date 2019/12/3 11:40
 */
public class DemoSchedule {

    public static void main(String[] args) throws SchedulerException, InterruptedException {

        /**
         * 1、创建调度器Scheduler
         */
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        /**
         * 创建JobDetail实例,并与PrintWordsJob类绑定(Job执行内容)
         */
        JobDetail jobDetail = JobBuilder.newJob(DemoJob.class)
                .withIdentity("job1", "triggerGroup1")
                .build();

        /**
         * 构建JobDetail实例 每隔1s执行一次
         */
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .startNow()//立即生效
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        /**
                         * 每隔1s执行一次
                         */
                        .withIntervalInSeconds(1)
                        .repeatForever()).build();//一直执行

        /**
         * 执行
         */
        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("-------scheduler start!---------");
        scheduler.start();

        /**
         * 运行一分钟以后睡眠
         */
        TimeUnit.MINUTES.sleep(1);
        scheduler.shutdown();
        System.out.println("------------scheduler shutdown!--------------");


    }

}


运行程序,可以看到程序每隔1s会打印出内容,且在一分钟后结束:

三、Quartz核心详解

下面就程序中出现的几个参数,看一下Quartz框架中的几个重要参数:

  • Job和JobDetail
  • JobExecutionContext
  • JobDataMap
  • Trigger、SimpleTrigger、CronTrigger

(1)Job和JobDetail
Job是Quartz中的一个接口,接口下只有execute方法,在这个方法中编写业务逻辑。
接口中的源码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.quartz;

public interface Job {
    void execute(JobExecutionContext var1) throws JobExecutionException;
}

JobDetail用来绑定Job,为Job实例提供许多属性:

  • name
  • group
  • jobClass
  • jobDataMap

JobDetail绑定指定的Job,每次Scheduler调度执行一个Job的时候,首先会拿到对应的Job,然后创建该Job实例,再去执行Job中的execute()的内容,任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。

为什么设计成JobDetail + Job,不直接使用Job


JobDetail定义的是任务数据,而真正的执行逻辑是在Job中。
这是因为任务是有可能并发执行,如果Scheduler直接使用Job,
就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,Sheduler每次执行,
都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。

(2)JobExecutionContext
JobExecutionContext中包含了Quartz运行时的环境以及Job本身的详细数据信息。
当Schedule调度执行一个Job的时候,就会将JobExecutionContext传递给该Job的execute()
中,Job就可以通过JobExecutionContext对象获取信息。
主要信息有:


//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.quartz;

import java.util.Date;

public interface JobExecutionContext {
    Scheduler getScheduler();

    Trigger getTrigger();

    Calendar getCalendar();

    boolean isRecovering();

    TriggerKey getRecoveringTriggerKey() throws IllegalStateException;

    int getRefireCount();

    JobDataMap getMergedJobDataMap();

    JobDetail getJobDetail();

    Job getJobInstance();

    Date getFireTime();

    Date getScheduledFireTime();

    Date getPreviousFireTime();

    Date getNextFireTime();

    String getFireInstanceId();

    Object getResult();

    void setResult(Object var1);

    long getJobRunTime();

    void put(Object var1, Object var2);

    Object get(Object var1);
}


# Quartz 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×