Quartz是什么

Quartz是一个功能强大的开源任务调度库,几乎可以集成到任何Java应用程序中,无论是超小型的独立应用还是超大型电子商务系统。

它常用于企业级应用中:

  • Driving Process Workflow:当新订单下达,可以安排一个30分钟内触发的任务,检查订单状态。
  • System Maintenance:安排每个工作日晚上11点将数据库内容转储到文件的任务。
  • Providing reminder services:提供提醒服务。

Quartz还支持集群模式和对JTA事务。

Quartz中的重要API及概念

http://www.quartz-scheduler.org/documentation/quartz-2.2.2/tutorials/

超重要API

  • Scheduler 和调度程序交互的主要API

    • 生命周期从SchedulerFactoru创建它开始,到调用shutdown方法结束。
    • 一旦Scheduler创建,任何关于scheduling相关的事,他都为所欲为:添加、删除、列出所有的Jobs和triggers、暂停触发器等。
    • 在start方法之前,不会做任何事情。
  • Job 你希望被调度器调度的任务组件接口。
    • 当Job的触发器触发时,调度程序的工作线程将调用execute方法。
    • 该方法接收一个JobExecutionContext 对象,为Job实例提供了丰富的运行时环境信息,比如:scheduler、trigger、jobDataMap、job、calendar、各种time等。
  • JobDetail 用于定义任务。
    • JobDetail对象由Quartz客户端在将job加入Scheduler提供,也就是你的程序。
    • 它包含了不同为job设置的属性,还有可以用来为job储存状态信息的JobDataMap。
    • 注意它和Job的区别,它实际上是Job实例的属性。【Job定义如何执行,JobDetail定义有何属性】
  • Trigger 触发任务执行。
    • 触发器可能具有与之关联的JobDataMap,以便于将特定于触发器触发的参数传递给Job。
    • Quartz提供了几种不同的触发器,SimpleTrigger和CronTrigger比较常用。
    • 如果你需要一次性执行作业或需要在给定的时间触发一个作业并重复执行N次且有两次执行间有延时delay,SimpleTrigger较为方便。
    • 如果你希望基于类似日期表触发执行任务,CronTrgger推荐使用。
  • JobBuilder 用于构建JobDetail的。
  • TriggerBuilder 用于构建Trigger的。

Quartz提供了各种各样的Builder类,定义了Domain Specific Language,且都提供了静态的创建方法,我们可以使用import static简化书写。

重要概念

  • Identity

    • 当作业和触发器在Quartz调度程序中注册时,会获得标识键。
    • JobKey和TriggerKey允许被置入group中,易于组织管理。
    • 唯一的,是name和group的组合标识。
  • JobDataMap
    • 是Map的实现,具有key-value相关操作,存储可序列化数据对象,供Job实例在执行时使用。
    • 可以使用usingJobData(key,value)在构建Jobdetail的时候传入数据,使用jobDetail.getJobDataMap()获取map。

Quartz设计理念:为什么设计Job和Trigger?

While developing Quartz, we decided that it made sense to create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits.

For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job. Another benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired, so that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define its associated job.

隔离schedule和schedule上执行的Job,优点是可见的:

可以独立于触发器创建作业并将其存储在作业调度程序中,并且许多触发器可以与同一作业相关联。这样的松耦合好处是什么?

  • 如果触发器过期,作业还可以保留在程序中,以便重新调度,而不必重新定义。
  • 如果你希望修改替换某个触发器,你不必重新定义其关联的作业。

最简单的Quartz使用案例

导入依赖

<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>

简单案例如下

public class QuartzTest {
// 你需要在start和shutdown之间执行你的任务。
public static void main(String[] args) { try {
// 从工厂中获取Scheduler示例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // 开始
scheduler.start(); // 定义Job,并将其绑定到HelloJob类中
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") // name 和 group
.usingJobData("username", "天乔巴夏") // 置入JobDataMap
.usingJobData("age", "20")
.withDescription("desc-demo")
.build(); // 触发Job执行,每40s执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow() // 立即开始
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build(); // 告诉 quartz 使用trigger来调度job
scheduler.scheduleJob(job, trigger);
// 关闭,线程终止
scheduler.shutdown(); } catch (SchedulerException se) {
se.printStackTrace();
}
} } @Slf4j
@NoArgsConstructor
public class HelloJob implements Job { @Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 从context中获取属性
JobDetail jobDetail = context.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
JobKey key = jobDetail.getKey();
Class<? extends Job> jobClass = jobDetail.getJobClass();
String description = jobDetail.getDescription(); String username = jobDataMap.getString("username");
int age = jobDataMap.getIntValue("age"); log.info("\nJobKey : {},\n JobClass : {},\n JobDesc : {},\n username : {},\n age : {}",
key, jobClass.getName(), description, username, age);
}
}

启动测试,打印日志如下:

01:23:12.406 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
01:23:12.414 [main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main
01:23:12.430 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
01:23:12.430 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.
01:23:12.432 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.
01:23:12.433 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.2) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. 01:23:12.433 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
01:23:12.433 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2
01:23:12.434 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
01:23:12.434 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
01:23:12.443 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
01:23:12.445 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'group1.job1', class=com.hyhwky.HelloJob
01:23:12.451 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
01:23:12.452 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
01:23:12.452 [DefaultQuartzScheduler_Worker-1] INFO com.hyhwky.HelloJob -
JobKey : group1.job1,
JobClass : com.hyhwky.HelloJob,
JobDesc : desc-demo,
username : 天乔巴夏,
age : 20

我们可以看到quartz已经被初始化了,初始化配置如下,在org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar!\org\quartz\quartz.properties

# 调度器配置
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 #trigger 容忍时间60s org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

更多的配置:Quartz Configuration Reference

Job实例和JobDetail

Job和JobDetail

  • Job是正在执行的作业实例,JobDetail是作业定义。
  • 一个Job可以创建多个JobDetail,拥有不同的JobDataMap。

这样定义有什么好处呢?举个例子吧,假设现在你定义了一个类实现了Job接口,比如:SendEmailJob。如果你希望根据用户的姓名,选择指定的人发送,那么你可以通过JobDataMap绑定参数传递进JobDetail中,也就是说我们需要创建两个不同的JobDetail,比如:SendEmailToSummerday和SendEmailToTQBX,他们拥有各自独立的JobDataMap,实现更加灵活。

Job的State和Concurrency

https://blog.csdn.net/fly_captain/article/details/83029440

@DisallowConcurrentExecution

该注解标注在Job类上,意思是不能并发执同一个JobDetail定义的多个实例,但可以同时执行多个不同的JobDetail定义的实例。

拿上面的例子继续举例,假设SendEmailJob标注了此注解,表明同一时间可以同时执行SendEmailToSummerday和SendEmailToTQBX,因为他们是不同的JobDetail,但是不能同时执行多个SendEmailToSummerday。

@PersistJobDataAfterExecution

该注解也标注在Job类上,告诉Scheduler正常执行完Job之后,重新存储更新一下JobDataMap。一般标注此注解的Job类应当考虑也加上@DisallowConcurrentExecution注解,以避免同时执行Job时出现JobDataMap存储的竞争。

Trigger常见使用

更多例子可以查看文档,非常详细:SimpleTriggerCronTrigger

构建一个触发器,该触发器将立即触发,然后每五分钟重复一次,直到小时 22:00:


import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*: SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger7", "group1")
.withSchedule(simpleSchedule()
.withIntervalInMinutes(5)
.repeatForever())
.endAt(dateOf(22, 0, 0))
.build();

构建一个触发器,该触发器将在周三上午 10:42 触发,在系统默认值以外的时区中:

import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*: trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 42 10 ? * WED")) // [秒] [分] [时] [月的第几天] [月] [一星期的第几天] [年(可选)]
.inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
.forJob(myJobKey)
.build();

Quartz存储与持久化

Job的持久化是非常重要的,如果Job不能持久化,一旦不再有与之关联的Trigger,他就会自动从调度程序中被删除。

Job存储器的类型:

类型 优点 缺点
RAMJobStore 不要外部数据库,配置容易,运行速度快 因为调度程序信息是存储在被分配给 JVM 的内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。另外因为存储到JVM内存里面,所以可以存储多少个 Job 和 Trigger 将会受到限制
JDBC 作业存储 支持集群,因为所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应用服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启而导致执行失败的任务 运行速度的快慢取决与连接数据库的快慢

具体的使用方法:http://www.quartz-scheduler.org/documentation/quartz-2.2.2/tutorials/tutorial-lesson-09.html

任务调度框架Quartz快速入门!的更多相关文章

  1. SpringBoot整合任务调度框架Quartz及持久化配置

    目录 本篇要点 SpringBoot与Quartz单机版快速整合 引入依赖 创建Job 调度器Scheduler绑定 自动配置,这里演示SimpleScheduleBuilder 手动配置,这里演示C ...

  2. Java任务调度框架Quartz入门

    Quartz[kwɔːts]:石英,其框架和名字一样简单朴素又不失魅力,在Java程序界,Quartz大名鼎鼎,很多Java应用几乎都集成或构建了一个定时任务调度系统,Quartz是一个定时任务调度框 ...

  3. 企业级任务调度框架Quartz(1) --企业应用中的任务调度介绍

    由于目前的工作内容为建行CLPM批处理业务的设计工作,所以很好的理解批处理所用的任务调度框架Quartz势在必行:为了能够更好的去服务于工作,也 为了提升自己,所以我学习了Quartz Job Sch ...

  4. 通过源码分析Java开源任务调度框架Quartz的主要流程

    通过源码分析Java开源任务调度框架Quartz的主要流程 从使用效果.调用链路跟踪.E-R图.循环调度逻辑几个方面分析Quartz. github项目地址: https://github.com/t ...

  5. [源码分析] 定时任务调度框架 Quartz 之 故障切换

    [源码分析] 定时任务调度框架 Quartz 之 故障切换 目录 [源码分析] 定时任务调度框架 Quartz 之 故障切换 0x00 摘要 0x01 基础概念 1.1 分布式 1.1.1 功能方面 ...

  6. Nodejs ORM框架Sequelize快速入门

    Nodejs ORM框架Sequelize快速入门 什么是ORM? 简单的讲就是对SQL查询语句的封装,让我们可以用OOP的方式操作数据库,优雅的生成安全.可维护的SQL代码.直观上,是一种Model ...

  7. Mybatis框架 的快速入门

    MyBatis 简介 什么是 MyBatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果 ...

  8. [jbdj]SpringMVC框架(1)快速入门

    1)springmvc快速入门(传统版) 步一:创建springmvc_demo一个web应用 步二:导入springioc,springweb , springmvc相关的jar包 步三:在/WEB ...

  9. ssm框架整合快速入门

    写在前面: 公司一直都是使用ssh框架(Struts2,Spring,Hibernate)来开发,但是现在外面的公司大多数都是使用的ssm框架,所以也有必要多学习一下外面的新技术.这里就快速搭建一个小 ...

随机推荐

  1. css实现元素环形旋转

    元素中心旋转效果记录 先上代码 //css代码 .header{   -webkit-animation:rotateImg 1s linear infinite;   /*rotateImg对应下方 ...

  2. Web 常见漏洞

    检测到目标URL存在http host头攻击漏洞 描述:为了方便的获得网站域名,开发人员一般依赖于HTTP Host header.例如,在php里用_SERVER["HTTP_HOST&q ...

  3. 第14.14节 爬虫实战准备:csdn博文点赞过程http请求和响应信息分析

    如果要对csdn博文点赞,首先要登录CSDN,然后打开一篇需要点赞的文章,如<第14.1节 通过Python爬取网页的学习步骤>按<第14.3节 使用google浏览器获取网站访问的 ...

  4. PyQt(Python+Qt)学习随笔:Qt Designer中QAbstractButton派生按钮部件autoExclusive属性

    autoExclusive 属性保留是否启用按钮的自动排它特性,如果启用了,则属于同一父部件的可选中按钮任何时候只能选中一个按钮:选中另一个按钮将自动取消选中先前选中的按钮,这个功能与排他性按钮组的功 ...

  5. [BJDCTF2020]Cookie is so stable && [GWCTF 2019]枯燥的抽奖

    [BJDCTF2020]Cookie is so stable 进入环境后看到有hint,点击之后查看源代码 提示我们cookie有线索 flag页面是: 需要输入一个username,或许这道题目是 ...

  6. PC微信[多开+免扫码+防撤回撤回提示+转存语音+自动收款+远程命令]

    PC端微信玩出了新花样,主要技术为Hook技术 有兴趣的小伙伴可以去了解下hook钩子技术 版本介绍: 增加转存语音到MP3(保存你重要的语音数据) 增加表图转存; 增加自动收转账和自动回复; 增加远 ...

  7. Scrum 冲刺第四天

    一.每日站立式会议 1.会议内容 1)进行每日工作汇报 张博愉: 昨天已完成的工作:搜寻测试相关的资料 今日工作计划:编写测试计划 工作中遇到的困难:对测试接触得较少,有点头疼 张润柏: 昨天已完成的 ...

  8. Python 表达式 i += x 与 i = i + x 等价吗?

    Python 表达式 i += x 与 i = i + x 等价吗? 看个例子 a = [1, 2, 3] b = a # 写法一 b += [4] # 写法二 # b = b + [4] print ...

  9. 前端开发超好用的截图、取色工具——snipaste

    最近发现一个很好用的前端截图,取色工具,并且基本功能是免费使用的,可以提升开发效率,拿出来跟大家分享一下. 该工具主要能实现的功能就是截图,并且截图可以以窗口形式置顶在窗口: 第二个主要功能就是可以取 ...

  10. 自动化管理平台rundeck的安装方法

    简介 RunDeck 是用 Java/Grails 写的开源工具,帮助用户在数据中心或者云环境中自动化各种操作和流程.通过命令行或者web界面,用户可以对任意数量的服务器进行操作,大大降低了对服务器自 ...