quartz简介

Quartz的概念并不是很复杂,简单说就是一个java的定时调度器,我们只需要搞明白几个概念,然后知道如何去开启和关闭一个定时任务

  • Job

表示一个工作,要执行的具体内容。此接口中只有一个方法 void execute(JobExecutionContext context)我们要去重写这个方法,来放置自己的任务逻辑。

  • JobDetail

JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。

  • Trigger

代表一个调度参数的配置,什么时候去调

  • Scheduler

代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了

  • Calendar

它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合。一个Trigger可以和多个Calendar关联, 以便排除或包含某些时间点。

  • ThreadPool

Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。

下图描述了Scheduler的内部组件结构,SchedulerContext提供Scheduler全局可见的上下文信息,每一个任务都对应一个JobDataMap,虚线表达的JobDataMap表示对应有状态的任务:

quartz1

quartz简单例子

1.引入maven

 <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>1.8.6</version>
</dependency>
<dependency>
        <groupId>javax.transaction</groupId>
        <artifactId>jta</artifactId>
        <version>1.1</version>
</dependency>

2.创建job任务

package com.chenfan.service;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Job;

import java.util.Date;


public class HelloQuartzJob implements Job{
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
        System.out.println("Hello, Quartz! - executing its JOB at "+ dateFormat.format(new Date()) + " by " + context.getTrigger().getCalendarName());
    }
}

3.调度任务

import java.sql.Date;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;


public class HelloQuartzScheduling {

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

        SchedulerFactory schedulerFactory = new StdSchedulerFactory();  
        Scheduler scheduler = schedulerFactory.getScheduler();	//创建scheduler容器

        JobDetail jobDetail = new JobDetail("helloQuartzJob",
                Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);	//	加载可执行调度程序

        SimpleTrigger simpleTrigger = new SimpleTrigger("simpleTrigger",
                Scheduler.DEFAULT_GROUP);   //  加载触发器,这里是简单触发器

        simpleTrigger.setStartTime(new Date(System.currentTimeMillis()));

        simpleTrigger.setRepeatInterval(5000);	// 5s执行一次
        simpleTrigger.setRepeatCount(10);	//	重复执行10次

        scheduler.scheduleJob(jobDetail, simpleTrigger);

        scheduler.start();
    }

}

4.执行结果

quartz2

Trigger触发器

Quartz有两大触发器,除了上面使用的SimpleTrigger外,就是CronTrigger。CronTrigger能够提供复杂的触发器表达式的支持。CronTrigger是基于Unix Cron守护进程,它是一个调度程序,支持简单而强大的触发器语法。

使用CronTrigger主要的是要掌握Cron表达式。Cron表达式包含6个必要组件和一个可选组件,如下表所示。

quartz3

特殊字符含义见下表

quartz4

Cron表达式举例

“30 * * * * ?” 每半分钟触发任务

“30 10 * * * ?” 每小时的10分30秒触发任务

“30 10 1 * * ?” 每天1点10分30秒触发任务

“30 10 1 20 * ?” 每月20号1点10分30秒触发任务

“30 10 1 20 10 ? * “ 每年10月20号1点10分30秒触发任务

“30 10 1 20 10 ? 2011” 2011年10月20号1点10分30秒触发任务

“30 10 1 ? 10 * 2011” 2011年10月每天1点10分30秒触发任务

“30 10 1 ? 10 SUN 2011” 2011年10月每周日1点10分30秒触发任务

“15,30,45 * * * * ?” 每15秒,30秒,45秒时触发任务

“15-45 * * * * ?” 15到45秒内,每秒都触发任务

“15/5 * * * * ?” 每分钟的每15秒开始触发,每隔5秒触发一次

“15-30/5 * * * * ?” 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次

“0 0/3 * * * ?” 每小时的第0分0秒开始,每三分钟触发一次

“0 15 10 ? * MON-FRI” 星期一到星期五的10点15分0秒触发任务

“0 15 10 L * ?” 每个月最后一天的10点15分0秒触发任务

“0 15 10 LW * ?” 每个月最后一个工作日的10点15分0秒触发任务

“0 15 10 ? * 5L” 每个月最后一个星期四的10点15分0秒触发任务

“0 15 10 ? * 5#3” 每个月第三周的星期四的10点15分0秒触发任务

将上面HelloQuartz例子中SimpleTrigger换成CronTrigger,代码如下。

public class HelloQuartzScheduling {
    public static void main(String[] args) throws SchedulerException, ParseException {

        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        JobDetail jobDetail = new JobDetail("helloQuartzJob",
                Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);
        String cronExpression = "30/4 * * * * ? 2017";

        CronTrigger cronTrigger = new CronTrigger("cronTrigger",
                Scheduler.DEFAULT_GROUP, cronExpression);

        scheduler.scheduleJob(jobDetail, cronTrigger);

        scheduler.start();
        //scheduler.shutdown(true);
    }

}

排除一段时间

使用Calender可以排除一些不需要定时的日期

  • CronCalendar:使用表达式排除某些时间段不执行

  • DailyCalendar:指定的时间范围内的每一天不执行

  • HolidayCalendar:排除节假日

  • MonthlyCalendar:排除月份中的数天

  • WeeklyCalendar:排除星期中的一天或多天

例子:

public class HelloQuartzScheduling {

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

        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        JobDetail jobDetail = new JobDetail("helloQuartzJob",
                Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

        Calendar cal = Calendar.getInstance();
        cal.set(2017, Calendar.OCTOBER, 1); // 国庆节

        HolidayCalendar holidayCal = new HolidayCalendar();
        holidayCal.addExcludedDate(cal.getTime()); // 排除该日期

        // addCalendar(String calName, Calendar calendar,
        //             boolean replace, boolean updateTriggers)
        scheduler.addCalendar("calendar", holidayCal, true, false);

        String cronExpression = "30/5 * * * * ?"; // 每5s触发任务        
        CronTrigger cronTrigger = new CronTrigger("cronTrigger",
                Scheduler.DEFAULT_GROUP, cronExpression);

        cronTrigger.setCalendarName("calendar");

        scheduler.scheduleJob(jobDetail, cronTrigger);

        scheduler.start();
    }

}

JobStore: 任务持久化

Quartz支持任务持久化,这可以让你在运行时增加任务或者对现存的任务进行修改,并为后续任务的执行持久化这些变更和增加的部分。中心概念是JobStore接口。默认的是RAMJobStore,它的优点是速度。因为所有的 Scheduler 信息都保存在计算机内存中,访问这些数据随着电脑而变快。而无须访问数据库或IO等操作,但它的缺点是将 Job 和 Trigger 信息存储在内存中的。因而我们每次重启程序,Scheduler 的状态,包括 Job 和 Trigger 信息都丢失了

quartz5