0


Quartz:定时任务调度框架

Quartz主要内容

Quartz是一个开源的任务调度框架,负责任务进度管理(就是一个在预先被纳入日程,当时间到达时,负责执行(或者通知)其他软件组件的系统),由OpenSymphony(一个开源组织)开发,这个框架进行了优良地解耦设计,
Quartz主要功能,就是在设定的时间内干什么事情,比如说把redis中的缓存数据与数据库中的数据进行同步、定时发送信息、设置一个周三才开始的活动。Quartz是一个基于Java实现的任务调度框架,应该说叫定时任务调度框架。在Java领域,有很多定时任务框架,这里简单对比一下目前比较流行的三款:

Quartz主要分为三大部分:

  • Job:定时执行的具体工作内容,想要调度的任务都必须实现 org.quartz.job 接口,然后实现接口中定义的 execute( ) 方法即可。
  • Trigger:触发器,指定运行参数,包括运行次数、运行开始时间和技术时间、运行时长等,如果想要凌晨1点执行备份数据的任务,那么 Trigger 就会设置凌晨1点执行该任务。其中 Trigger 又分为 SimpleTriggerCronTrigger 两种。
  • Scheduler:调度器,将Job和Trigger组装起来,使定时任务被真正执行,主要负责基于Trigger设置的时间来启动、暂停、恢复、停止和触发时间修改对应的任务。

下图是Quartz主要的关系图:

文字化的描述就是,Job通过实现类与Trigger进行绑定,一个Job可以绑定多个Trigger(实现了Quartz的异步通知),但是一个Trigger只能绑定一个Job,且Job的实现类与Trigger通过Group和name来标识唯一性,Quartz是使用多线程来处理任务的。

Quartz集群

Quartz集群中每个节点是一个独立的Quartz任务应用,它又管理者其他节点。该集群需要分别对每个节点分别启动或停止,独立的Quartz节点并不与另一个节点或是管理节点通信。Quartz应用是通过共有相同数据库表来感知到另一应用。也就是说只有使用持久化JobStore存储Job和Trigger才能完成Quartz集群部署方案。
Quartz的集群部署方案是分布式的,没有负责集中管理的节点,而是利用数据库行锁的方式来实现集群环境下的并发控制。Quartz主要有两个行锁:
锁名解释STATE_ACCESS状态访问锁Trigger_ACCESS触发器访问锁
一个scheduler实例在集群模式下首先获取行锁才行。Quartz集群争用触发器行锁,锁被占用只能等待,获取触发器行锁之后,先获取需要等待触发的其他触发器信息。
定时任务的诸多要素,如任务名称、数量、状态、运行频率、运行时间等,是要存储起来的。JobStore,就是用来存储任务和触发器相关的信息的。Quartz 中有两种存储任务的方式,一种在在内存(RAMJobStore),一种是在数据库(JDBCJobStore)。
Quartz 默认的 JobStore 是 RAMJobstore,也就是把任务和触发器信息运行的信息存储在内存中,用到了 HashMap、TreeSet、HashSet 等等数据结构,如果程序崩溃或重启,所有存储在内存中的数据都会丢失。所以我们需要把这些数据持久化到磁盘。

# Default Properties file for use by StdSchedulerFactory# to create a Quartz Scheduler Instance, if a different# properties file is not explicitly specified.#

org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true

org.quartz.jobStore.misfireThreshold: 60000
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore  # 标识Quartz的持久化存储是RAM

Quartz中相关类

  • Job接口: 自己写的“定时程序”实现此接口的void execute(JobExecutionContext arg0)方法,Job还有一类为有状态的StatefulJob接口,如果我们需要在上一个作业执行完后,根据其执行结果再进行下次作业的执行,则需要实现此接口。
publicclassXXXJobsimplementsJob{@AutowiredprivateXXXService xxxService;// 自己写的实现void execute()方法@Overridepublicvoidexecute(JobExecutionContext context)throwsJobExecutionException{
        log.debug("xxxQueueJob start...");// 分布式锁,如果获取失败则返回XXXJob proxy =ApplicationContextUtil.getBean(getClass());
        proxy.jobHandler();
        log.debug("xxxQueueJob end...");}@JobToken@RedisLock(expiration =20L)publicvoidjobHandler(){// 定时任务核心逻辑}}
  • Trigger抽象类: 调度类(Scheduler)在时间到时调用此类,再由trigger类调用指定的定时程序。Quertz中提供了两类触发器为:SimpleTrigger,CronTrigger。前者用于实现比较简单的定时功能,例如几点开始,几点结束,隔多长时间执行,共执行多少次等,后者提供了使用表达式来描述定时功能,因此适用于比较复杂的定时描述,例如每个月的最后一个周五,每周的周四等。 - SimpleTrigger:简单触发器,支持定义任务执行的间隔时间,执行次数的规则有两种,一是定义重复次数,二是定义开始时间和结束时间。如果同时设置了结束时间与重复次数,先结束的会覆盖后结束的,以先结束的为准。- CronTrigger:基于Cron表达式的触发器。- CalendarIntervalTrigger:基于日历的触发器,比简单触发器更多时间单位,且能智能区分大小月和平闰年。- DailyTimeIntervalTrigger:基于日期的触发器,如每天的某个时间段。

Trigger是有状态的:NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED,状态之间转换关系如下图所示:

Trigger trigger =TriggerBuilder.newTrigger().withIdentity("trigger1","trigger-group").startNow()//立即生效.forJob(jobDetail).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)//每隔3s执行一次.repeatForever())// 永久循环.build();
  • JobDetail类: 具体某个定时程序的详细描述,包括Name,Group,JobDataMap等。
JobDataMap jobDataMap = jobDetail.getJobDataMap();String name = jobDetail.getKey().getName();String group = jobDetail.getKey().getGroup();String jobName = jobDetail.getJobClass().getName();
  • JobExecutionContext类: 定时程序执行的run-time的上下文环境,用于得到当前执行的Job的名字,配置的参数等。
  • JobDataMap类: 用于描述一个作业的参数,参数可以为任何基本类型例如String,float等,也可为某个对象的引用.
  • JobListener,TriggerListener接口: 用于监听触发器状态和作业扫行状态,在特写状态执行相应操作。
  • JobStore类: 在哪里执行定进程序,可选的有在内存中,在数据库中。
publicclassHelloJobimplementsJob{@Overridepublicvoidexecute(JobExecutionContext context)throwsJobExecutionException{Object tv1 = context.getTrigger().getJobDataMap().get("t1");Object tv2 = context.getTrigger().getJobDataMap().get("t2");Object jv1 = context.getJobDetail().getJobDataMap().get("j1");Object jv2 = context.getJobDetail().getJobDataMap().get("j2");Object sv =null;try{
            sv = context.getScheduler().getContext().get("skey");}catch(SchedulerException e){
            e.printStackTrace();}System.out.println(tv1+":"+tv2);System.out.println(jv1+":"+jv2);System.out.println(sv);System.out.println("hello:"+LocalDateTime.now());}}-----------------------------------------------------------------------------------------publicclassTest{publicstaticvoidmain(String[] args)throwsSchedulerException{//创建一个schedulerScheduler scheduler =StdSchedulerFactory.getDefaultScheduler();
        scheduler.getContext().put("skey","svalue");//创建一个TriggerTrigger trigger =TriggerBuilder.newTrigger().withIdentity("trigger1","group1").usingJobData("t1","tv1").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();
        trigger.getJobDataMap().put("t2","tv2");//创建一个jobJobDetail job =JobBuilder.newJob(HelloJob.class).usingJobData("j1","jv1").withIdentity("myjob","mygroup").build();
        job.getJobDataMap().put("j2","jv2");//注册trigger并启动scheduler
        scheduler.scheduleJob(job,trigger);
        scheduler.start();}}

Quartz监听器

在 Quartz 中三个核心模块分别是 Job、Trigger、Scheduler,既然 Quartz中存在监听器,相应的,这三者也分别有对应的监听器。监听器的作用便是用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知。监听器也有作用域,主要分为

  • 全局监听器:能够接收到所有的Job/Trigger的事件通知;
  • 局部监听器:只能接收在其上注册Job或者Trigger的事件;

三核心监听器:

  • JobListener

任务调度中,与任务 Job 相关的事件包括: Job 开始要执行的提示,执行完成的提示,接口如下:

packageorg.quartz;publicinterfaceJobListener{StringgetName();//用于获取改JobListener 的名称// Scheduler 在 JobDetail 将要被执行时调用这个方法voidjobToBeExecuted(JobExecutionContext var1);// cheduler 在 JobDetail 即将被执行,但又被 TriggerListener 否决时会调用该方法voidjobExecutionVetoed(JobExecutionContext var1);// Scheduler 在 JobDetail 被执行之后调用这个方法voidjobWasExecuted(JobExecutionContext var1,JobExecutionException var2);}

将JobListener绑定到Scheduler中

//监听所有的Job
scheduler.getListenerManager().addJobListener(newSimpleJobListener(),EverythingMatcher.allJobs());//监听特定的Job
scheduler.getListenerManager().addJobListener(newSimpleJobListener(),KeyMatcher.keyEquals(JobKey.jobKey("HelloWorld1_Job","HelloWorld1_Group")));//监听同一任务组的Job
scheduler.getListenerManager().addJobListener(newSimpleJobListener(),GroupMatcher.jobGroupEquals("HelloWorld2_Group"));//监听两个任务组的Job
scheduler.getListenerManager().addJobListener(newSimpleJobListener(),OrMatcher.or(GroupMatcher.jobGroupEquals("HelloWorld1_Group"),GroupMatcher.jobGroupEquals("HelloWorld2_Group")));
  • TriggerListener

任务调度中,与触发器 Trigger 相关的事件包括: 触发器触发、触发器未正常触发、触发器完成等,接口如下:

packageorg.quartz;importorg.quartz.Trigger.CompletedExecutionInstruction;publicinterfaceTriggerListener{StringgetName();//用于获取触发器的名称// 当与监听器相关联的Trigger被触发,Job上的**execute()**方法将被执行时,Scheduler就调用该方法voidtriggerFired(Trigger var1,JobExecutionContext var2);//在 Trigger 触发后,Job 将要被执行时由 Scheduler 调用这个方法。// TriggerListener 给了一个选择去否决 Job 的执行。假如这个方法返回 true,这个 Job 将不会为此次 Trigger 触发而得到执行booleanvetoJobExecution(Trigger var1,JobExecutionContext var2);// Scheduler 调用这个方法是在 Trigger 错过触发时voidtriggerMisfired(Trigger var1);// Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方法voidtriggerComplete(Trigger var1,JobExecutionContext var2,CompletedExecutionInstruction var3);}

将TriggerListener绑定到Scheduler中:

//监听所有的Trigger
scheduler.getListenerManager().addTriggerListener(newSimpleTriggerListener("SimpleTrigger"),EverythingMatcher.allTriggers());//监听特定的Trigger
scheduler.getListenerManager().addTriggerListener(newSimpleTriggerListener("SimpleTrigger"),KeyMatcher.keyEquals(TriggerKey.triggerKey("HelloWord1_Job","HelloWorld1_Group")));//监听一组Trigger
scheduler.getListenerManager().addTriggerListener(newSimpleTriggerListener("SimpleTrigger"),GroupMatcher.groupEquals("HelloWorld1_Group"));//移除监听器
scheduler.getListenerManager().removeTriggerListener("SimpleTrigger");
  • SchedulerListener

SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler发生严重错误,关闭scheduler等。接口如下:

packageorg.quartz;publicinterfaceSchedulerListener{// 用于部署JobDetail时调用voidjobScheduled(Trigger var1);// 用于卸载JobDetail时调用voidjobUnscheduled(TriggerKey var1);// 当一个 Trigger 来到了再也不会触发的状态时调用这个方法voidtriggerFinalized(Trigger var1);// Scheduler 调用这个方法是发生在一个 Trigger 或 Trigger 组被暂停时voidtriggerPaused(TriggerKey var1);voidtriggersPaused(String var1);// Scheduler 调用这个方法是发生成一个 Trigger 或 Trigger 组从暂停中恢复时voidtriggerResumed(TriggerKey var1);voidtriggersResumed(String var1);voidjobAdded(JobDetail var1);voidjobDeleted(JobKey var1);voidjobPaused(JobKey var1);voidjobsPaused(String var1);voidjobResumed(JobKey var1);voidjobsResumed(String var1);voidschedulerError(String var1,SchedulerException var2);voidschedulerInStandbyMode();// 当Scheduler处于StandBy模式时,调用该方法voidschedulerStarted();voidschedulerStarting();voidschedulerShutdown();voidschedulerShuttingdown();voidschedulingDataCleared();}

将SchedulerListener绑定到Scheduler中

//创建监听
scheduler.getListenerManager().addSchedulerListener(newSimpleSchedulerListener());//移除监听
scheduler.getListenerManager().removeSchedulerListener(newSimpleSchedulerListener());

Quartz使用流程

  • 引入Maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency>
  • 新建Job,实现想要执行的任务
importorg.quartz.Job;importorg.quartz.JobExecutionContext;importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;publicclassSimpleJobimplementsJob{@Overridepublicvoidexecute(JobExecutionContext jobExecutionContext){// 创建一个事件,下面仅创建一个输出语句作演示System.out.println(Thread.currentThread().getName()+"--"+DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));}}
  • 创建Trigger与Scheduler,执行定时任务
importcom.quartz.demo.schedule.SimpleJob;importorg.junit.jupiter.api.Test;importorg.quartz.*;importorg.quartz.impl.StdSchedulerFactory;importjava.util.Date;importjava.util.concurrent.TimeUnit;publicclassSimpleQuartzTest{/*
     * 基于时间间隔的定时任务
     */@TestpublicvoidsimpleTest()throwsSchedulerException,InterruptedException{// 1、创建Scheduler(调度器)SchedulerFactory schedulerFactory =newStdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();// 2、创建JobDetail实例,并与SimpleJob类绑定(Job执行内容)JobDetail jobDetail =JobBuilder.newJob(SimpleJob.class).withIdentity("job1","group1").build();// 3、构建Trigger(触发器),定义执行频率和时长Trigger trigger =TriggerBuilder.newTrigger()// 指定group和name,这是唯一身份标识.withIdentity("trigger-1","trigger-group").startNow()//立即生效.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)//每隔2s执行一次.repeatForever())// 永久执行.build();//4、将Job和Trigger交给Scheduler调度
        scheduler.scheduleJob(jobDetail, trigger);// 5、启动Scheduler
        scheduler.start();// 休眠,决定调度器运行时间,这里设置30sTimeUnit.SECONDS.sleep(30);// 关闭Scheduler
        scheduler.shutdown();}}


参考:https://blog.csdn.net/mu_wind/article/details/124257719
cron在线生成:https://cron.qqe2.com/

标签: java 大数据 架构

本文转载自: https://blog.csdn.net/weixin_43537820/article/details/129678544
版权归原作者 Felix.Lee 所有, 如有侵权,请联系我们删除。

“Quartz:定时任务调度框架”的评论:

还没有评论