
概念: quartz 是一个基于JAVA的定时任务调度框架
案例:
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version></dependency>JobDetail job = JobBuilder.newJob(SchedulerTs.class).withIdentity("job1", "group1").usingJobData("name", "zs").build();Date endDate = DateUtils.addMinutes(new Date(), 2);SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger", "triggerGroup").withSchedule(SimpleScheduleBuilder.simpleSchedule()// 任务执行间隔.withIntervalInSeconds(10)// 重复执行次数.withRepeatCount(10)).forJob(job).endAt(endDate).startNow().build();StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();Scheduler scheduler = stdSchedulerFactory.getScheduler();// 配置任务scheduler.scheduleJob(job, trigger);scheduler.start();
使用、上手难度: 简单
效果已经实现了、那么这个是怎么实现的呢、很费解、所以花了一早上时间扒了扒源码、解惑
首先介绍几个关键的类:
StdSchedulerFactory 调度工厂、Scheduler 调度工具(类)、QuartzSchedulerThread 任务执行线程、SchedulerRepository 单例的调度仓库 、 JobDetail 任务job封装接口、SimpleTrigger 触发器
现在看着有点多、记不住. 蓝色部分忽略、他只是建造者模式的应用、封装了 很多属性方法、SchedulerRepository 单例的调度仓库 也可以忽略、他只是一个map 用来存放 调度类的,并且也能够避免相同调度类的重复创建;
重头戏: 找到切入点 StdSchedulerFactory 调度工厂 是如何获取到 调度类 Scheduler 的,并且 Scheduler.start 和 scheduleJob 方法做了什么,我认为看懂这两块,基本就算差不多了
创建 StdSchedulerFactory 对象,只是一个空对象,什么也没有做、关键点在于StdSchedulerFactory 的 getScheduler 方法, 我们先看源码

到现在比较明了了. 主要工作在 initialize 方法 和 instantiate 方法做的,我们逐个分析
initialize 源码.只粘贴关键代码. 实际上他也只是做了文件解析、将文件中的配置信息交给Properties,然后将 配置信息交给 工厂类的属性 cfg 对象.这个对象只是在properties 外面封装了一层.本质还是一个properties、配置信息包含一些线程数、执行间隔啥的. 这个就是配置、具体不做讨论

instantiate 源码、这个方法做的 任务比较多、涉及到 QuartzSchedulerThread 类的创建和启动、调度仓库调度器的插入、前面的配置信息就是在这一步装配到任务上的,废话不多说、直接看源码


现在又会有一个疑惑、一个线程执行一次就结束了、他怎么做到一直监听到有新任务进来的呢? 关键在于 一个while 循环 和 sigLock 对象的 await 与 notifyAll 操作,下面图放了 这个线程run方法的动作, 到现在已经明确 instantiate 执行完之后线程就是已经启动的了


现在我们再去看看 StdSchedulerFactory 的 scheduleJob 方法做了啥,将当前任务 保存到了 triggersByKey 和 jobsByKey 中 ,然后 交给了 listener 和 plugs 监听处理

最后一步、启动 StdSchedulerFactory.start

通过 sigLock 的notifyAll 通知 quartzSchedulerThread 线程继续执行.
自己实现的任务是在何时被调用的呢? QuartzSchedulerThread::run 来寻找答案

新建的shell 是一个线程、initialize 关键步骤,newJob


找到了、反射 实例话 job类、得到了我们写好的对象
runThread(shell) 执行了 shell 线程,run方法做了什么 我们看下,job.execute 任务被执行了.
完美,我看到的是这样如果有疏漏麻烦评论区指正,感激,结尾附上思维导图、相对来说更加详细

