守时使命结构Quartz-(一)Quartz入门与Demo建立

一、什么是Quartz

什么是Quartz?

Quartz是OpenSymphony开源组织在Job scheduling范畴又一个开源项目,完全由Java开发,能够用来履行守时使命,类似于java.util.Timer。可是相较于Timer, Quartz增加了许多功用:

  • 持久性作业 – 便是保持调度守时的状况;
  • 作业办理 – 对调度作业进行有效的办理;

大部分公司都会用到守时使命这个功用。 拿火车票购票来说,当你下单后,后台就会刺进一条待付出的task(job),一般是30分钟,超越30min后就会履行这个job,去判别你是否付出,未付出就会取消此次订单;当你付出完结之后,后台拿到付出回调后就会再刺进一条待消费的task(job),Job触发日期为火车票上的出发日期,超越这个时刻就会履行这个job,判别是否运用等。

在咱们实践的项目中,当Job过多的时分,肯定不能人工去操作,这时分就需求一个使命调度结构,帮咱们主动去履行这些程序。那么该如何完成这个功用呢?

(1)首要咱们需求界说完成一个守时功用的接口,咱们能够称之为Task(或Job),如守时发送邮件的task(Job),重启机器的task(Job),优惠券到期发送短信提醒的task(Job),完成接口如下:

定时任务框架Quartz

(2)有了使命之后,还需求一个能够完成触发使命去履行的触发器,触发器Trigger最基本的功用是指定Job的履行时刻,履行间隔,运转次数等。

定时任务框架Quartz

(3)有了Job和Trigger后,怎么样将两者结合起来呢?即怎样指定Trigger去履行指定的Job呢?这时需求一个Schedule,来负责这个功用的完成。

定时任务框架Quartz

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

  • 调度器:Scheduler
  • 使命:JobDetail
  • 触发器:Trigger,包括SimpleTrigger和CronTrigger

二、Quartz Demo建立

下面来运用Quartz建立一个最基本的Demo。 1、导入依靠的jar包:

org.quartz-scheduler quartz 2.3.0

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

/** * Created by wanggenshen * Date: on 2018/7/7 16:28. * Description: 打印恣意内容 */
public class PrintWordsJob 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,履行使命:

/** * Created by wanggenshen * Date: on 2018/7/7 16:31. * Description: XXX */
public class MyScheduler { 
    public static void main(String[] args) throws SchedulerException, InterruptedException {
        // 1、创立调度器Scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        // 2、创立JobDetail实例,并与PrintWordsJob类绑定(Job履行内容)
        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)
                                        .withIdentity("job1", "group1").build();
        // 3、构建Trigger实例,每隔1s履行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .startNow()//当即生效
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1)//每隔1s履行一次
                .repeatForever()).build();//一直履行
        //4、履行
        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核心详解

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

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

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

定时任务框架Quartz

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对象获取信息。 首要信息有:

定时任务框架Quartz

(3)JobExecutionContext JobDataMap完成了JDK的Map接口,能够以Key-Value的形式存储数据。 JobDetail、Trigger都能够运用JobDataMap来设置一些参数或信息, Job履行execute()办法的时分,JobExecutionContext能够获取到JobExecutionContext中的信息: 如:

JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)                        .usingJobData("jobDetail1", "这个Job用来测验的")
                  .withIdentity("job1", "group1").build();
 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
      .usingJobData("trigger1", "这是jobDetail1的trigger")
      .startNow()//当即生效
      .withSchedule(SimpleScheduleBuilder.simpleSchedule()
      .withIntervalInSeconds(1)//每隔1s履行一次
      .repeatForever()).build();//一直履行

仿制

Job履行的时分,能够获取到这些参数信息:

 @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("jobDetail1"));
        System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("trigger1"));
        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));
    }

仿制

(4)Trigger、SimpleTrigger、CronTrigger

  • Trigger

Trigger是Quartz的触发器,会去通知Scheduler何时去履行对应Job。

new Trigger().startAt():表明触发器首次被触发的时刻;
new Trigger().endAt():表明触发器完毕触发的时刻;

仿制

  • SimpleTrigger SimpleTrigger能够完成在一个指守时刻段内履行一次作业使命或一个时刻段内屡次履行作业使命。 下面的程序就完成了程序运转5s后开始履行Job,履行Job 5s后完毕履行:
Date startDate = new Date();
startDate.setTime(startDate.getTime() + 5000);
 Date endDate = new Date();
 endDate.setTime(startDate.getTime() + 5000);
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData("trigger1", "这是jobDetail1的trigger")
                .startNow()//当即生效
                .startAt(startDate)
                .endAt(endDate)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1)//每隔1s履行一次
                .repeatForever()).build();//一直履行

仿制

  • CronTrigger

CronTrigger功用十分强大,是根据日历的作业调度,而SimpleTrigger是精准指定间隔,所以比较SimpleTrigger,CroTrigger愈加常用。CroTrigger是根据Cron表达式的,先了解下Cron表达式: 由7个子表达式组成字符串的,格式如下:

[秒] [分] [小时] [日] [月] [周] [年]

Cron表达式的语法比较复杂, 如:* 30 10 ? * 1/5 * 表明(从后往前看) [指定年份] 的[ 周一到周五][指定月][不指定日][上午10时][30分][指定秒]

又如:00 00 00 ? * 10,11,12 1#5 2018 表明2018年10、11、12月的第一周的星期五这一天的0时0分0秒去履行使命。

下面是给的一个例子:

定时任务框架Quartz

可通过在线生成Cron表达式的工具:cron.qqe2.com/ 来生成自己想要的表达式。

定时任务框架Quartz

下面的代码就完成了每周一到周五上午10:30履行守时使命

/** * Created by wanggenshen * Date: on 2018/7/7 20:06. * Description: XXX */
public class MyScheduler2 { 
    public static void main(String[] args) throws SchedulerException, InterruptedException {
        // 1、创立调度器Scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        // 2、创立JobDetail实例,并与PrintWordsJob类绑定(Job履行内容)
        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)
                .usingJobData("jobDetail1", "这个Job用来测验的")
                .withIdentity("job1", "group1").build();
        // 3、构建Trigger实例,每隔1s履行一次
        Date startDate = new Date();
        startDate.setTime(startDate.getTime() + 5000);
        Date endDate = new Date();
        endDate.setTime(startDate.getTime() + 5000);
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData("trigger1", "这是jobDetail1的trigger")
                .startNow()//当即生效
                .startAt(startDate)
                .endAt(endDate)
                .withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018"))
                .build();
        //4、履行
        scheduler.scheduleJob(jobDetail, cronTrigger);
        System.out.println("--------scheduler start ! ------------");
        scheduler.start();
        System.out.println("--------scheduler shutdown ! ------------");
    }
}