目录
quartz原理介绍
原理白话
java的定时任务解决方案中,quartz本身就是一个完整、强大的解决方案。现有的各种定时任务解决方案框架也都是基于quartz实现。那么我们来介绍一下quartz如何实现的定时任务,以及它做了哪些事情。
定时任务涉及到两方面,定时触发以及任务的执行。任务的执行是需要专门的线程池的,不能妨碍到任务的触发工作。那么触发是怎么实现的?最笨的办法:轮询。这是由对复杂任务触发时间表达式的支持决定的,因为触发规则如此多,我们必须不断地去检查是否有需要触发的任务。
quartz设计实现
接下来从quartz的组成要素以及设计实现的角度来进行介绍:
Job、Trigger、QuartzSchedulerThread、Scheduler、JobStores
前三者分别是执行的任务、该任务的触发器(计算触发时间等)、任务触发线程
Scheduler则是这些相关元素的整合、管理者,提供了控制定时任务调度器的接口比如start、shutdown等,在这些接口里将对QuartzSchedulerThread里的动作产生影响,并通知给注册的listener。scheduler中还有SchedulerSignaler对象,该对象被jobStore使用,用来通知Scheduler进行一些相关操作。
JobStores里存储了所有的job以及trigger信息,供QuartzSchedulerThread查询需要触发的任务等使用。
这些元素的加载过程如下:
StdSchedulerFactory中的instantiate方法加载配置,实例化Scheduler,在Scheduler的实例化方法中,构造QuartzSchedulerThread,并注册listener以及plugin.
然后QuartzSchedulerThread就开始对定时任务的调度,我们通过Scheduler来对该过程进行控制。
quartz支持的自定义
quartz提供了定时任务的实现,许多参数都可以自定义,比如scheduler,可以是本地实现StdScheduler,也可以是远程实现RemoteScheduler;
执行定时任务的线程池 org.quartz.threadPool;
触发定时任务的线程池 org.quartz.threadExecutor.class;
job信息的存储器 org.quartz.jobStore.class ,可以支持保存在内存中,或者数据库中,而在数据库中又分为Scheduler自己控制事务与否
trigger也有不同的实现,比如SimpleTrigger、CronTrigger等,这就允许使用不同的方式来定义定时任务的触发时间
xxl-job
quartz已经如此强大,为什么还需要定时任务的解决方案框架比如xxl-job?
随着数据、服务压力的增大,分布式调度的定时任务需求出现了;再有,我们需要一些便捷的定时任务类型库,比如javaBean、shell脚本,我们需要现成的执行组件;还有任务之间的关系、触发次序、依赖的维护。
等等需求,这就需要一个成熟的解决方案框架,xxl-job便是如此一个实现。
原理介绍
首先它是基于quartz来做的,只是封装了调度的任务,也即JobDetail的builder,使得产生的任务实际上执行的操作是远程方法调用。框架的部署就分为执行端与调用端两部分。调用端兼任务管理、展示的职能,提供任务的方便增删改查以及日志查看,运行任务控制。
这里有执行器的概念,一个执行器代表一组执行客户端,一个任务可以由多个执行客户端执行,通过调度算法实现任务执行压力的分担。具体的交互泳道图如下:
服务端关键类:XxlJobDynamicScheduler
客户端关键类:XxlJobExecutor
具体介绍见:http://www.xuxueli.com/xxl-job/#/
我的定制
基于我们公司的任务有拆分为更小粒度的子任务的需求,并且使用人员需要在总任务的运行结果层面上关注所有的任务运行情况。一方面也是因为本人对精确化控制的追求,希望对任务的运行做更小粒度的控制,我们对xxl-job支持的父子任务调度运行部分做了增强。
原本xxl-job对父子任务的支持是在父任务运行结束之后,如果运行成功,会触发其下的子任务运行,并有相应的调度触发备注。增强后的父子任务调度、结果更新流程如下: