什么是quartz?
Quartz是一个完全由 Java 编写的开源任务调度框架。
我们经常会遇到一些问题:
想每个月27号,提醒信用卡还款;
想每隔1小时,提醒一下,累了,站起来活动一下;
想每个月定时发送邮件,等等。
总结起来就是,在一个有规律的时间点做某件事。
quartz可满足复杂触发条件下的定时任务调度,比如每月的周一和周五 10点 15分执行。
quartz集群可保证系统的高可用性,即使一个节点崩了,也能保证任务的执行。
集群环境下,一个任务某个时间点只会在一个节点上运行。
核心概念
- Job 表示一个工作,要执行的具体内容
- JobDetail 表示任务的定义,Job 是任务的执行逻辑
- Trigger 代表一个调度参数的配置,什么时候去调
- Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。
quartz集群应用
集群中的节点放在不同的服务器上,称为水平集群。
节点放在同一台机器上,称为垂直集群,存在着单点故障问题。
Quartz可以借助关系数据库和JDBC作业存储支持集群。
数据库脚本
链接:https://pan.baidu.com/s/1BpDTVRwtN6_VVJqTx9flNQ
提取码:49ie
搭建spring boot环境
以定时发送邮件为例,每隔1分钟发送一次,邮件发送功能忽略,不是本例重点。
开发工具:Intellij IDEA
添加maven 依赖
配置
- 配置application.yml
server: port: ${PORT:8090}spring: application: name: learn-quartz datasource: druid: url: ${MYSQL_URL:jdbc:mysql://192.168.0.113:3306/quartz?characterEncoding=utf-8&useSSL=false} username: root password: 123456 driverClassName: com.mysql.cj.jdbc.Driver initialSize: 5 #初始建立连接数量 minIdle: 5 #最小连接数量 maxActive: 20 #最大连接数量 maxWait: 10000 #获取连接最大等待时间,毫秒 testOnBorrow: true #申请连接时检测连接是否有效 testOnReturn: false #归还连接时检测连接是否有效 timeBetweenEvictionRunsMillis: 60000 #配置间隔检测连接是否有效的时间(单位是毫秒) minEvictableIdleTimeMillis: 300000 #连接在连接池的最小生存时间(毫秒) quartz: job-store-type: jdbc #数据库方式 jdbc: initialize-schema: never #不初始化表结构 properties: org: quartz: scheduler: instanceId: AUTO #默认主机名和时间戳生成实例ID,可以是任何字符串,但对于所有调度程序来说,必须是唯一的 对应qrtz_scheduler_state INSTANCE_NAME字段 instanceName: clusteredScheduler #quartzScheduler jobStore: class: org.quartz.impl.jdbcjobstore.JobStoreTX #持久化配置 driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #我们仅为数据库制作了特定于数据库的代理 useProperties: false #以指示JDBCJobStore将JobDataMaps中的所有值都作为字符串,因此可以作为名称 - 值对存储而不是在BLOB列中以其序列化形式存储更多复杂的对象。从长远来看,这是更安全的,因为您避免了将非String类序列化为BLOB的类版本问题。 tablePrefix: QRTZ_ #数据库表前缀 misfireThreshold: 60000 #在被认为“失火”之前,调度程序将“容忍”一个Triggers将其下一个启动时间通过的毫秒数。默认值(如果您在配置中未输入此属性)为60000(60秒)。 clusterCheckinInterval: 5000 #设置此实例“检入”*与群集的其他实例的频率(以毫秒为单位)。影响检测失败实例的速度。 isClustered: true #打开群集功能 threadPool: #连接池 class: org.quartz.simpl.SimpleThreadPool threadCount: 10 threadPriority: 5 threadsInheritContextClassLoaderOfInitializingThread: true
- 定义Job
public class EmailJob extends QuartzJobBean { @Value("${server.port}") String port; @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { String time = DateUtil.now(); System.out.println(time + " send email,server port:" + port); }}
- 配置QuartzConfig.java
@Configurationpublic class QuartzConfig { @Bean public JobDetail jobSendEmailDetails() { return JobBuilder.newJob(EmailJob.class).withIdentity("emailJobId") .storeDurably().build(); } /** * 1分钟1次,会平均分配到每个节点上 * @return */ @Bean public Trigger jobOrderCheckTrigger() { return TriggerBuilder.newTrigger().forJob(jobSendEmailDetails()) .withIdentity("sendEmailTriggerId") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")) .build(); }}
创建2个应用
选择Edit Configurations, 在spring boot目录下创建quartz1和quartz2, VM options中分别输入-DPORT=8090和-DPORT=8091, 启动两个实例,同一个任务会在两个实例中轮流执行,效果图: