什么是Quartz
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能。
Quartz就是一种任务调度计划。
- 它是由OpenSymphony提供的、开源的、java编写的强大任务调度框架
- 几乎可以集成到任何规模的运用程序中,如简单的控制台程序,复杂的大规模分布式电子商务系统
- 可用于创建简单的或复杂的计划任务
- 包含很多企业级功能,如支持JTA和集群等
大部分公司都会用到定时任务这个功能。
拿火车票购票来说,当你下单后,后台就会插入一条待支付的task(job),一般是30分钟,超过30min后就会执行这个job,去判断你是否支付,未支付就会取消此次订单;当你支付完成之后,后台拿到支付回调后就会再插入一条待消费的task(job),Job触发日期为火车票上的出发日期,超过这个时间就会执行这个job,判断是否使用等。
在我们实际的项目中,当Job过多的时候,肯定不能人工去操作,这时候就需要一个任务调度框架,帮我们自动去执行这些程序。那么该如何实现这个功能呢?
(1)首先我们需要定义实现一个定时功能的接口,我们可以称之为Task(或Job),如定时发送邮件的task(Job),重启机器的task(Job),优惠券到期发送短信提醒的task(Job),实现接口如下:
(2)有了任务之后,还需要一个能够实现触发任务去执行的触发器,触发器Trigger最基本的功能是指定Job的执行时间,执行间隔,运行次数等。
(3)有了Job和Trigger后,怎么样将两者结合起来呢?即怎样指定Trigger去执行指定的Job呢?这时需要一个Schedule,来负责这个功能的实现。
上面三个部分就是Quartz的基本组成部分:
- 调度器:Scheduler
- 任务:JobDetail
- 触发器:Trigger,包括SimpleTrigger和CronTrigger
本篇文章,主要从Quartz框架核心组件,Quartz基本运行原理,Quartz核心概念和Quartz基本功能实现(代码)等方面来介绍Quartz。
Quartz
当要深入研究一个技术时,研究它的体系结构和内部运行原理,不失为一种较好的方式。同理,我们在研究Quartz时,也采用类似的方法,
下图为Quartz的大致结构图。
Quartz关键组件
Quartz比较关键的两个核心组件分别为Job和Trigger
- job--表示任务是什么
- trigger--表示何时触发任务
Quartz几个关键概念
IJob
IJob表示一个接口,该接口只有一个方法签名
public interface IJob { void Execute(JobExecutionContext context); }
在Quartz中,所有的job任务,必须实现该接口
public class MyJob : IJob { public void Execute(JobExecutionContext context) { Console.WriteLine("Quartz基本功能测试。"); } }
JobDetail
JobDetail,顾名思义,就是表示关于每个Job的相关信息,它主要包括两个核心组件,即Job Task和JobData Map
Trigger
Trigger,表示触发器,根据配置规则来触发执行计划调度job,它主要包括两个核心组件,即SimpleTrigger和CronTrigger
IJobStore
IJobStore,表述任务存储器,主要存储job和trigger相关信息。
ISchedulerFactory
ISchedulerFactory,表示任务计划工厂,用来管理任务计划IScheduler。
IScheduler
IScheduler,表述任务计划,它相当于一个容器,具体job和job相关trigger就能够被注入其中,从而实现任务计划调度。其主要常用的方法:
- Start --启动执行计划
- Shutdowm --关闭执行计划
接口Code:
namespace Quartz { public interface IScheduler { bool IsStarted { get; } string SchedulerName { get; } string SchedulerInstanceId { get; } bool InStandbyMode { get; } bool IsShutdown { get; } IJobFactory JobFactory { set; } string[] JobGroupNames { get; } string[] TriggerGroupNames { get; } SchedulerContext Context { get; } IList GlobalJobListeners { get; } string[] CalendarNames { get; } IList GlobalTriggerListeners { get; } ISet TriggerListenerNames { get; } ISet JobListenerNames { get; } IList SchedulerListeners { get; } void AddCalendar(string calName, ICalendar calendar, bool replace, bool updateTriggers); void AddGlobalJobListener(IJobListener jobListener); void AddGlobalTriggerListener(ITriggerListener triggerListener); void AddJob(JobDetail jobDetail, bool replace); void AddJobListener(IJobListener jobListener); void AddSchedulerListener(ISchedulerListener schedulerListener); void AddTriggerListener(ITriggerListener triggerListener); bool DeleteCalendar(string calName); bool DeleteJob(string jobName, string groupName); ICalendar GetCalendar(string calName); string[] GetCalendarNames(); IList GetCurrentlyExecutingJobs(); IJobListener GetGlobalJobListener(string name); ITriggerListener GetGlobalTriggerListener(string name); JobDetail GetJobDetail(string jobName, string jobGroup); IJobListener GetJobListener(string name); string[] GetJobNames(string groupName); SchedulerMetaData GetMetaData(); ISet GetPausedTriggerGroups(); Trigger GetTrigger(string triggerName, string triggerGroup); ITriggerListener GetTriggerListener(string name); string[] GetTriggerNames(string groupName); Trigger[] GetTriggersOfJob(string jobName, string groupName); TriggerState GetTriggerState(string triggerName, string triggerGroup); bool Interrupt(string jobName, string groupName); bool IsJobGroupPaused(string groupName); bool IsTriggerGroupPaused(string groupName); void PauseAll(); void PauseJob(string jobName, string groupName); void PauseJobGroup(string groupName); void PauseTrigger(string triggerName, string groupName); void PauseTriggerGroup(string groupName); bool RemoveGlobalJobListener(IJobListener jobListener); bool RemoveGlobalJobListener(string name); bool RemoveGlobalTriggerListener(ITriggerListener triggerListener); bool RemoveGlobalTriggerListener(string name); bool RemoveJobListener(string name); bool RemoveSchedulerListener(ISchedulerListener schedulerListener); bool RemoveTriggerListener(string name); DateTime? RescheduleJob(string triggerName, string groupName, Trigger newTrigger); void ResumeAll(); void ResumeJob(string jobName, string groupName); void ResumeJobGroup(string groupName); void ResumeTrigger(string triggerName, string groupName); void ResumeTriggerGroup(string groupName); DateTime ScheduleJob(Trigger trigger); DateTime ScheduleJob(JobDetail jobDetail, Trigger trigger); void Shutdown(bool waitForJobsToComplete); void Shutdown(); void Standby(); void Start(); void StartDelayed(TimeSpan delay); void TriggerJob(string jobName, string groupName); void TriggerJob(string jobName, string groupName, JobDataMap data); void TriggerJobWithVolatileTrigger(string jobName, string groupName); void TriggerJobWithVolatileTrigger(string jobName, string groupName, JobDataMap data); bool UnscheduleJob(string triggerName, string groupName); } }
核心UML图
命名空间
不同版本的Quartz命名空间有所区别,但差别不大,如下为版本1.0.3命名空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
using
Quartz;
using
Quartz.Core;
using
Quartz.Impl;
using
Quartz.Impl.AdoJobStore;
using
Quartz.Impl.AdoJobStore.Common;
using
Quartz.Impl.Calendar;
using
Quartz.Impl.Matchers;
using
Quartz.Impl.Triggers;
using
Quartz.Listener;
using
Quartz.Logging;
using
Quartz.Logging.LogProviders;
using
Quartz.Simpl;
using
Quartz.Spi;
using
Quartz.Util;
using
Quartz.Xml;
using
Quartz.Xml.JobSchedulingData20;
using
System;
|
关键组件继承关系
在Quartz中,许多组件是可以通过配置来促使作业执行的,如线程程序(Tread Procedure)决定如何执行计划任务线程(Quartz Scheduler Thread)
代码
本示例,我们将使用.net 控制台程序,基于VS2017来使用Quartz建立一个任务:
任务要求:要求在控制台每隔2秒输出:Quartz基本功能测试。
1.首先使用Nuget下载Quartz
本示例使用的Quartz版本为1.0.3
2.按照如下步骤操作
代码:
第一阶段:创建实现IJob接口的MyJob类
public class MyJob : IJob { public void Execute(JobExecutionContext context) { Console.WriteLine("Quartz基本功能测试。"); } }
第二阶段:按规则调用Quartz组件
static void Main(string[] args) { //每个2秒执行一次 string cronParam = "*/2 * * * * ?"; //创建计划任务抽象工厂 ISchedulerFactory sf = new StdSchedulerFactory(); //创建计划任务 IScheduler sched = sf.GetScheduler(); //创建job JobDetail job = new JobDetail("myJob","group", typeof(MyJob)); //创建触发器 Trigger trigger = new CronTrigger("myTrigger","group",cronParam); //将job和trigger注入到计划任务中 sched.ScheduleJob(job, trigger); //启动计划任务 sched.Start(); //关闭计划任务 //sched.Shutdown(); Console.Read(); }
3.测试结果