什么是quartz?

Quartz是一个完全由 Java 编写的开源任务调度框架。

我们经常会遇到一些问题:

想每个月27号,提醒信用卡还款;

想每隔1小时,提醒一下,累了,站起来活动一下;

想每个月定时发送邮件,等等。

总结起来就是,在一个有规律的时间点做某件事。

quartz可满足复杂触发条件下的定时任务调度,比如每月的周一和周五 10点 15分执行。

quartz集群可保证系统的高可用性,即使一个节点崩了,也能保证任务的执行。

集群环境下,一个任务某个时间点只会在一个节点上运行。

核心概念

  1. Job 表示一个工作,要执行的具体内容
  2. JobDetail 表示任务的定义,Job 是任务的执行逻辑
  3. Trigger 代表一个调度参数的配置,什么时候去调
  4. Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。



java 调度 java 调度 失火_springboot集成quartz


quartz集群应用

集群中的节点放在不同的服务器上,称为水平集群。

节点放在同一台机器上,称为垂直集群,存在着单点故障问题。

Quartz可以借助关系数据库和JDBC作业存储支持集群。


java 调度 java 调度 失火_springboot集成quartz_02


数据库脚本

链接:https://pan.baidu.com/s/1BpDTVRwtN6_VVJqTx9flNQ

提取码:49ie

搭建spring boot环境

以定时发送邮件为例,每隔1分钟发送一次,邮件发送功能忽略,不是本例重点。

开发工具:Intellij IDEA

添加maven 依赖


java 调度 java 调度 失火_bc_03


配置

  • 配置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, 启动两个实例,同一个任务会在两个实例中轮流执行,效果图:


java 调度 java 调度 失火_数据库_04

quartz1


java 调度 java 调度 失火_数据库_05

quartz2