searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Quartz 一个灵活的调度器

2023-10-30 01:54:31
6
0

1. 简介

Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB作业预构 建,JavaMail及其它,支持cron-like表达式等等。

2. Quartz架构

3. 核心类

Job:

接口,表示具体要执行的业务逻辑。在实际使用中需要自定义类实现execute方法。

默认情况下,每次Job被执行时都会创建新的Job实例,而执行后的Job实例会被垃圾回收器回收。所以Job是无状态的。

@PersistJobDataAfterExecution 注解表示每一次Job执行成功后会更新JobDataMap的值(存在JobExecutionContext中),后面的Job再执行时会调用新的JobDataMap以此实现状态信息记录。如果不加该注解每次JobDataMap都是默认值。使用该注解建议同时使用@DisallowConcurrentExecution注解使得同一JobDetail不同同时创建多个Job实例,避免并发产生冲突。

@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class SaleJob implements Job {
    String sellMan;

    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println(String.format("%s在%s售出了一件商品",sellMan,Utils.getCurrentFormatTime()));
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        int count = jobDataMap.getInt("count") + 1;
        System.out.println(String.format("目前一共已经售出了%d件商品",count));
    }

    public void setSellMan(String sellMan) {
        this.sellMan = sellMan;
    }
}

JobDetail

封装了Job的信息,可以由JobBuilder创建。主要参数包括

  1. key : JobDetail的唯一标识,由“组名.任务名”构成。
  2. jobClass : 保存了Job的类字节码,用于使用反射的方式创建Job实例。
  3. JobDataMap:用于保存可供Job调用的信息,会被封装到JobExecutionContext 中。
  4. durable:没有活动的trigger与JobDetail关联时JobDetail会被Shceduler回收,将durable参数设置为真则即使没有活动的trigger与该JobDetail关联,Scheduler也不会删除该JobDetail。
  5. requestRecovery: 表示Scheduler宕机重启后会不会恢复该JobDetail
            JobDetail saleJob = JobBuilder.newJob().ofType(SaleJob.class).withIdentity("saleJOb","testGroup")
                    .storeDurably().usingJobData("count",0).build();

注意在一个Scheduler中JobDetail的key是唯一的,不得重复。

Trigger:

用来定义任务的触发时间,主要分为SimpleTrigger和CronTrigger。不过在谈这两者之前先谈谈Trigger的公共属性。

  1. jobKey: 表示当trigger触发时执行的Job的唯一标识
  2. startTime: 表示触发器开始工作的时间
  3. endTime: 表示触发器结束工作的时间
  4. Priority优先级:默认是5,表示当线程池中的资源不够用时那个Trigger会被优先触发。
  5. misfireInstructions: 表示错过触发时的策略,默认为MISFIRE_INSTRUCTION_SMART_POLICY,除此之外还有:MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY,MISFIRE_INSTRUCTION_FIRE_NOW,MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT,MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT,MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT,MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT。
  6. Calendar: org.quartz.Calendar对象(不是util.Calendar),表示跳过触发的日期。
  7. JobDataMap: 和JobDetail一致,会被存储在JobExcutionContex中。

SimpleTrigger常用于描述只执行一次或从某个时间点开始以固定间隔执行若干次。其可以通过SimpleScheduleBuilder来描述。

Trigger triggerZhangSan = TriggerBuilder.newTrigger().withIdentity("jonTrigger1","testGroup")
                .forJob(saleJob).usingJobData("sellMan","张三").startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();

CronTrigger用于描述更加复杂的触发条件,在构建时需要传入Cron表达式.

Trigger triggerLiSi = TriggerBuilder.newTrigger().withIdentity("jonTrigger2","testGroup")
                .forJob(saleJob).usingJobData("sellMan","李四").startNow().withSchedule(CronScheduleBuilder.cronSchedule(JobCron)).build();

Scheduler:

      Scheduler调度着任务的执行以及任务执行所需要的资源

Listener (JobListener/ TriggerListener/ SchedulerListener)

      Listener是通过AOP实现的,主要作用是接收和处理调度器回调的事件。正对不同的对象有不同的Listener与之相匹配。在实现Listener之后需要将其加入Scheduler.LisenerManager中进行管理。

public class SaleJobListener implements JobListener {
    public String getName() {
        return "saleJobListener";
    }

    public void jobToBeExecuted(JobExecutionContext context) {
        System.out.println(context.getMergedJobDataMap().getString("sellMan") + "正在招待客户。");
    }

    public void jobExecutionVetoed(JobExecutionContext context) {

    }

    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        System.out.println("恭喜" + context.getMergedJobDataMap().getString("sellMan") + "完成销售任务。");
    }
}

JobStore

      JobStore负责记录你提供到调度器的所有“工作数据”:所有的Job、所有的Trigger、所有的Calendar(org.quartz.Calendar)等等。不建议在代码中使用JobStore实例而是在配置文件中进行配置。目前官方定义的JobStore有三种

  1. RAMJobStore: 故名思意,使用RAM作为存储介质。速度最快,配置简单,但程序崩溃后信息会丢失
  2. JDBCJobStore: 通过JDBC将数据保存在数据库中。实现相对复杂,速度较慢,但支持集群模式。在使用之前需要在对应的数据库中进行建表。
  3. TerracottaJobStore: 性能介于RAMJobStore和JDBCJObStore之间。

4. Quartz分布式调度

Quartz是支持集群的,但只有当JobStore配置为JDBCStore时才支持集群操作。所有的节点公用一个数据库服务,通过数据库行锁实现分布式锁。

下面具体讲讲JDBCStore所依赖的表。

JDBCStore使用的表都是以QRTZ_开头,

  1. QRTZ_BLOB_TRIGGERS :自定义的triggers使用blog类型进行存储在这张表中
  2. QRTZ_CALENDARS:
  3. QRTZ_CRON_TRIGGERS:
  4. QRTZ_CRON_FIRED_TRIGGERS: 存储已经触发的trigger相关信息
  5. QRTZ_JOB_DETAILS:
  6. QRTZ_LOCKS: 存储锁,节点在执行调度时需要先获取需要锁锁名所在行的写锁,由于写锁的互斥性实现了分布式锁。
  7. QRTZ_PAUSED_TRIGGER_GRPS: 存放暂停掉的触发器
  8. QRTZ_SCHEDULER_STATE: 存储所有节点的scheduler,会定期检查scheduler是否失效
  9. QRTZ_SIMPLE_TRIGGES
  10. QRTZ_SIMPROP_TRIGGERS : 存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器
  11. QRTZ_TRIGGERS: 存储定义的trigger
0条评论
0 / 1000
杨****攀
3文章数
0粉丝数
杨****攀
3 文章 | 0 粉丝
杨****攀
3文章数
0粉丝数
杨****攀
3 文章 | 0 粉丝
原创

Quartz 一个灵活的调度器

2023-10-30 01:54:31
6
0

1. 简介

Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB作业预构 建,JavaMail及其它,支持cron-like表达式等等。

2. Quartz架构

3. 核心类

Job:

接口,表示具体要执行的业务逻辑。在实际使用中需要自定义类实现execute方法。

默认情况下,每次Job被执行时都会创建新的Job实例,而执行后的Job实例会被垃圾回收器回收。所以Job是无状态的。

@PersistJobDataAfterExecution 注解表示每一次Job执行成功后会更新JobDataMap的值(存在JobExecutionContext中),后面的Job再执行时会调用新的JobDataMap以此实现状态信息记录。如果不加该注解每次JobDataMap都是默认值。使用该注解建议同时使用@DisallowConcurrentExecution注解使得同一JobDetail不同同时创建多个Job实例,避免并发产生冲突。

@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class SaleJob implements Job {
    String sellMan;

    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println(String.format("%s在%s售出了一件商品",sellMan,Utils.getCurrentFormatTime()));
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        int count = jobDataMap.getInt("count") + 1;
        System.out.println(String.format("目前一共已经售出了%d件商品",count));
    }

    public void setSellMan(String sellMan) {
        this.sellMan = sellMan;
    }
}

JobDetail

封装了Job的信息,可以由JobBuilder创建。主要参数包括

  1. key : JobDetail的唯一标识,由“组名.任务名”构成。
  2. jobClass : 保存了Job的类字节码,用于使用反射的方式创建Job实例。
  3. JobDataMap:用于保存可供Job调用的信息,会被封装到JobExecutionContext 中。
  4. durable:没有活动的trigger与JobDetail关联时JobDetail会被Shceduler回收,将durable参数设置为真则即使没有活动的trigger与该JobDetail关联,Scheduler也不会删除该JobDetail。
  5. requestRecovery: 表示Scheduler宕机重启后会不会恢复该JobDetail
            JobDetail saleJob = JobBuilder.newJob().ofType(SaleJob.class).withIdentity("saleJOb","testGroup")
                    .storeDurably().usingJobData("count",0).build();

注意在一个Scheduler中JobDetail的key是唯一的,不得重复。

Trigger:

用来定义任务的触发时间,主要分为SimpleTrigger和CronTrigger。不过在谈这两者之前先谈谈Trigger的公共属性。

  1. jobKey: 表示当trigger触发时执行的Job的唯一标识
  2. startTime: 表示触发器开始工作的时间
  3. endTime: 表示触发器结束工作的时间
  4. Priority优先级:默认是5,表示当线程池中的资源不够用时那个Trigger会被优先触发。
  5. misfireInstructions: 表示错过触发时的策略,默认为MISFIRE_INSTRUCTION_SMART_POLICY,除此之外还有:MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY,MISFIRE_INSTRUCTION_FIRE_NOW,MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT,MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT,MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT,MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT。
  6. Calendar: org.quartz.Calendar对象(不是util.Calendar),表示跳过触发的日期。
  7. JobDataMap: 和JobDetail一致,会被存储在JobExcutionContex中。

SimpleTrigger常用于描述只执行一次或从某个时间点开始以固定间隔执行若干次。其可以通过SimpleScheduleBuilder来描述。

Trigger triggerZhangSan = TriggerBuilder.newTrigger().withIdentity("jonTrigger1","testGroup")
                .forJob(saleJob).usingJobData("sellMan","张三").startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();

CronTrigger用于描述更加复杂的触发条件,在构建时需要传入Cron表达式.

Trigger triggerLiSi = TriggerBuilder.newTrigger().withIdentity("jonTrigger2","testGroup")
                .forJob(saleJob).usingJobData("sellMan","李四").startNow().withSchedule(CronScheduleBuilder.cronSchedule(JobCron)).build();

Scheduler:

      Scheduler调度着任务的执行以及任务执行所需要的资源

Listener (JobListener/ TriggerListener/ SchedulerListener)

      Listener是通过AOP实现的,主要作用是接收和处理调度器回调的事件。正对不同的对象有不同的Listener与之相匹配。在实现Listener之后需要将其加入Scheduler.LisenerManager中进行管理。

public class SaleJobListener implements JobListener {
    public String getName() {
        return "saleJobListener";
    }

    public void jobToBeExecuted(JobExecutionContext context) {
        System.out.println(context.getMergedJobDataMap().getString("sellMan") + "正在招待客户。");
    }

    public void jobExecutionVetoed(JobExecutionContext context) {

    }

    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        System.out.println("恭喜" + context.getMergedJobDataMap().getString("sellMan") + "完成销售任务。");
    }
}

JobStore

      JobStore负责记录你提供到调度器的所有“工作数据”:所有的Job、所有的Trigger、所有的Calendar(org.quartz.Calendar)等等。不建议在代码中使用JobStore实例而是在配置文件中进行配置。目前官方定义的JobStore有三种

  1. RAMJobStore: 故名思意,使用RAM作为存储介质。速度最快,配置简单,但程序崩溃后信息会丢失
  2. JDBCJobStore: 通过JDBC将数据保存在数据库中。实现相对复杂,速度较慢,但支持集群模式。在使用之前需要在对应的数据库中进行建表。
  3. TerracottaJobStore: 性能介于RAMJobStore和JDBCJObStore之间。

4. Quartz分布式调度

Quartz是支持集群的,但只有当JobStore配置为JDBCStore时才支持集群操作。所有的节点公用一个数据库服务,通过数据库行锁实现分布式锁。

下面具体讲讲JDBCStore所依赖的表。

JDBCStore使用的表都是以QRTZ_开头,

  1. QRTZ_BLOB_TRIGGERS :自定义的triggers使用blog类型进行存储在这张表中
  2. QRTZ_CALENDARS:
  3. QRTZ_CRON_TRIGGERS:
  4. QRTZ_CRON_FIRED_TRIGGERS: 存储已经触发的trigger相关信息
  5. QRTZ_JOB_DETAILS:
  6. QRTZ_LOCKS: 存储锁,节点在执行调度时需要先获取需要锁锁名所在行的写锁,由于写锁的互斥性实现了分布式锁。
  7. QRTZ_PAUSED_TRIGGER_GRPS: 存放暂停掉的触发器
  8. QRTZ_SCHEDULER_STATE: 存储所有节点的scheduler,会定期检查scheduler是否失效
  9. QRTZ_SIMPLE_TRIGGES
  10. QRTZ_SIMPROP_TRIGGERS : 存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器
  11. QRTZ_TRIGGERS: 存储定义的trigger
文章来自个人专栏
猫猫的学习计划
3 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0