一、Quartz-核心要素

基本介绍

一、简介

Quartz是一个优秀的开源任务调度框架,完全基于Java实现,作用相当于一个定时器,可以在指定的时间点或时间间隔执行任务。可以使用在如”月底总结”,”每日结算”等需要在指定时间执行任务的需求中。

二、特点

  • 强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求。
  • 灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式。
  • 分布式和集群能力,quartz能够使用多个单独quartz程序作为节点共用一套数据库表来实现集群

核心接口

先来一波Quartz核心关系图
核心关系图

一、任务调度器-Scheduler

1.作用

Scheduler可以进行增加、删除及显示任务Job与触发器Trigger,并且可以进行如开始、暂停一个触发器Trigger等一系列与调度相关的工作。

2.创建

创建Scheduler需要通过StdSchedulerFactoryDirectSchedulerFactory工厂来创建。由于DirectSchedulerFactory需要详细的手工编码来进行设置,使用起来不太方便,所以一般情况下会通过StdSchedulerFactory来创建任务调度器。

3.生命周期

一个调度器的生命周期为通过SchedulerFactory创建,直到执行其shutdown()方法。

4工厂配置

StdSchedulerFactory用于创建Scheduler,其依赖于一系列的属性来决定如何产生Scheduler,而为其配置属性的常用方式有以下两种

  • quartz.properties配置文件

通过使用quartz.properties配置文件来为StdSchedulerFactory提供配置信息,这也是推荐使用的一种方式,方便后期维护。

当调用StdSchedulerFactory的无参initialize方法,StdSchedulerFactory会试图从quartz.properties文件中加载。有一定的加载顺序:首先会检查System.getProperty("org.quartz.properties")中是否有设置其他属性文件名,如果没有,尝试从当前工作目录中加载quartz.properties文件,如果没找到则会到项目的classpath中加载quartz.properties文件。如果还是没有,Quartz将自动加载jar包中默认的quartz.properties文件。简而言之一般直接将quartz.properties文件放到资源文件目录下即可。

关于quartz.properties配置文件的详细说明在第六章《配置详解》中

  • Properties对象

调用StdSchedulerFactory的有参initialize(properties)方法,通过java提供的Properties对象来完成对调度工厂的属性配置,劣势在于属性都用硬编码的方式写死在代码中,难于维护

  • 其他方法

此外还能通过属性文件或者属性文件的InputStream来进行属性配置,不常用就不说了

5.代码示例

这里为了方便,使用Properties对象的方式进行演示

    public static Scheduler createScheduler(JobDetail jobDetail, Trigger trigger){
        //创建调度工厂
        StdSchedulerFactory factory = new StdSchedulerFactory();
        //创建属性对象
        Properties props = new Properties();
        //线程池定义
        props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool");
        //设置Scheduler的线程数
        props.put("org.quartz.threadPool.threadCount", "10");
        Scheduler scheduler = null;
        try {
            //进行属性初始化
            factory.initialize(props);
            //创建Scheduler
            scheduler = factory.getScheduler();
            //设置触发器和执行的任务详情
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return scheduler;
    }

之后通过获取到的Scheduler对象调用start()shutdown()进行任务的开始和结束

二、触发器-Trigger

Trigger是用于定义调度时间的元素,即按照什么时间规则去执行任务。Quartz中主要提供了四种类型的TriggerSimpleTriggerCronTirggerDateIntervalTrigger,和NthIncludedDayTrigger。项目中使用较多的是SimpleTriggerCronTirgger,其中SimpleTrigger与java中提供的Timer类似,无法指定精确的执行日期,只能指定从某一个时间开始,以一定的时间间隔执行任务。而CronTirgger即可以指定简单的时间间隔,也可以指定精确日期,基本上满足一般的业务需求。

1.屬性

Trigger中有一些共同属性,这些属性可以通过TriggerBuilder来进行设置。主要有以下共同属性:
- triggerKey:触发器的唯一标识,由名称和组名联合组成,便于调度器查找、调用。
- jobKey:任务的唯一标识,当触发器被触发时,确定应该执行哪个任务
- startTime:触发器第一次触发的开始时间
- endTime:触发器结束时间

2.Calendars

Quartz提供了与Trigger关联的Calendars对象,当你希望在某一时间不想去触发触发器时,可以使用Calendars对象。Calendars需要在Scheduler定义过程中,通过scheduler.addCalendar()进行初始化和注册。

3.未启动指令

未启动指令用于当Trigger未正常触发时,是否恢复执行的场景,默认会使用smart policy指令。

Scheduler开启时,它将搜索所有未启动的持久化的触发器,然后基于触发器各自配置的”未启动指令”来更新触发器。

4.优先级

当在同一时间存在多个触发器时,Quartz可能没有足够的资源立即触发所有的触发器,我们可以通过设置每个Trigger的优先级来指定优先触发哪个触发器,默认的优先级为5,可取任意的整型值,包括正数或负数。

5.SimpleTrigger

SimpleTrigger用于规定时间执行一次或在规定的时间段以一定的时间间隔重复触发执行任务,主要属性有:开始时间、结束时间(优先于重复次数)、重复次数、重复时间间隔。

6.CronTrigger

CronTrigger支持复杂的调度。基于cron表达式,CronTrigger支持类似日历的重复间隔,而非单一的时间间隔。

7.代码示例
public class MyTriggers {

    /**
     * 示例
     * 设置公共属性
     */
    Trigger trigger = newTrigger()
            //设置触发器标识
            .withIdentity("myTrigger")
            //设置触发器优先级
            .withPriority(1)
            //设置触发时间,dailyAtHourAndMinute为cronTriggerBuilder的方法,每天09:30
            .withSchedule(dailyAtHourAndMinute(9,30)
                    //设置未启动指令
                    .withMisfireHandlingInstructionFireAndProceed())
            //设置执行的任务
            .forJob("myJob")
            //排除myHolidays中设置的日期
            .modifiedByCalendar("myHolidays")
            //创建触发器
            .build();

    /**
     * 示例
     * 通过TriggerBuilder创建SimpleTrigger
     */
    Trigger simpleTrigger =  newTrigger()
            //通过名字、组名唯一标识
            .withIdentity("simpleTrigger","groupOne")
            //设置开始时间,可为0,表示触发则执行
            .startAt(futureDate(5, DateBuilder.IntervalUnit.MINUTE))
            //设置SimpleTrigger调度属性
            .withSchedule(simpleSchedule()
                    //设置间隔时间为1分
                    .withIntervalInSeconds(1)
                    //设置重复次数20次
                    .withRepeatCount(20))
            //设置结束时间
            .endAt(dateOf(11, 0, 0))
            //指定执行的任务
            .forJob("simpleJob", "groupOne")
            //创建触发器
            .build();

    /**
     * 示例
     * 通过TriggerBuilder创建CronTrigger
     */
    Trigger cronTrigger = newTrigger()
        //设置触发器唯一标识
        .withIdentity("cronTrigger", "groupOne")
        //设置开始时间
        .startNow()
        //设置CronTrigger属性
        .withSchedule(cronSchedule("0 42 10 * * ?")
                //设置时间区域
                .inTimeZone(TimeZone.getTimeZone("Asia/Shanghai")))
        //设置执行任务
        .forJob("cronJob", "groupOne")
        //创建触发器
        .build();
}

三、任务-Job

Job即为调度任务中需要执行的任务类,将需要调度的Java类继承Job并将需要实现的功能放在其execute方法中即可将该Java类作为一个Job使用

1.execute

Job接口中提供了一个execute(JobExecutionContext context)方法,其中JobExecutionContext对象让Job能访问Quartz运行环境的所有信息和Job本身的明细数据,即Scheduler上与该Job相关联的JobDetailTrigger

2.种类&属性

Job主要有两种类型的Job:无状态的和有状态的。对于同一个trigger来说,有状态的job不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。有状态的Job可以理解为多次Job调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,而默认的无状态Job每次调用时都会创建一个新的JobDataMap

Job主要有两种属性:volatilitydurability,其中volatility表示任务是否被持久化到数据库存储,而durability表示在没有trigger关联的时候任务是否被保留。两者都是在值为true的时候任务被持久化或保留。一个job可以被多个trigger关联,但是一个trigger只能关联一个job

3.注解

继承了Job的类上常用的注解为@PersistJobDataAfterExecution@DisallowConcurrentExecution

  • @PersistJobDataAfterExecution的作用在于持久化保存在JobDataMap中的传递参数,使得多次执行Job,可以获取传递参数的状态信息。

  • @DisallowConcurrentExecution的作用是同一个时刻,同一个任务只能执行一次,不能并行执行多个同一任务。但多个不同的任务是可以同时执行的。

4.代码示例
public class MyJob implements Job {
    private static final Logger logger = LoggerFactory.getLogger(MyJob.class);

    public void execute(JobExecutionContext context){
        //获取任务名和任务组名
        JobDetail jobDetail = context.getJobDetail();
        logger.info("Job name and group:" + jobDetail.getKey());
        //获取Job状态信息
        Integer count = (Integer)jobDetail.getJobDataMap().get("count");
        logger.info("Count:" + count);
        //修改状态信息,测试@PersistJobDataAfterExecution带来的持久化效果
        jobDetail.getJobDataMap().put("count", count + 1);
        //获取调度器名
        Scheduler scheduler = context.getScheduler();
        try {
            logger.info("Scheduler name:" + scheduler.getSchedulerName());
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

四、任务详情-JobDetail

JobDetail是作为Job实例进行定义的,部署在Scheduler上的每一个Job只创建一个JobDetail实例。

注意!注册到Scheduler上的不是Job对象,而是JobDetail实例。Job的实例要到该执行它们的时候才会实例化出来。每次Job 被执行,一个新的Job实例会被创建。

1.JobDataMap

可以使用JobDataMap来定义Job的状态,JobDataMap中可以存入key-value对,这些数据可以在Job实现类中进行传递和访问。这是向Job传送配置信息的便捷方法。
Job能通过JobExecutionContext对象获取JobDetail对象访问JobDataMap

2.代码示例
    public static JobDetail createJobDetail() {
        //通过JobBuilder创建JobDetail
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                //设置任务名和任务组名组成任务唯一标识
                .withIdentity("myJob", "groupOne")
                //使用Job状态
                .usingJobData("count", 0)
                //构建JobDetail
                .build();
        return jobDetail;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值