一、什么是 Quartz Quartz 是一个完全由 Java 编写的开源作业调度框架,是 OpenSymphony 开源组织在 Job scheduling 领域又一个开源项目。Quartz 可以用来执行定时任务,类似于 java.util.Timer。
Quartz 核心概念 Job & JobDetail: 定义任务具体执行的逻辑 Trigger:触发器,定义任务执行的方式、间隔 Scheduler:任务调度器,所有的任务都是从这里开始。 Job 表示一个工作,要执行的具体内容。此接口中只有一个方法
1 void execute (JobExecutionContext context)
JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
简单类比一下,假设当你在 12306 抢到票后,你需要在 30 分钟内完成付款,否则订单将会被取消。对于这个过程来说后台就会插入一条待支付的 Job ,到了 30min 后就会执行这个 Job ,去判断你是否支付,未支付就会取消此次订单;而当你支付完成之后,后台拿到支付回调后就会再插入一条待使用的 Job ,触发时间为火车票上的出发日期,到了出发时间后就会执行这个 Job ,判断是否被使用。而这些不同的Job ,都需要一个能够实现触发任务去执行的触发器(Trigger ),最后使用调度容器(Schedule )来调度这两者。
在使用 Scheduler 之前,需要实例化 , scheduler 实例化后,可以启动(start)、暂停(stand-by)、停止(shutdown)。
Scheduler 的生命期,从 SchedulerFactory 创建它时开始,到 Scheduler 调用 shutdown()方法时结束;Scheduler 被创建后,可以增加、删除和列举 Job 和 Trigger,以及执行其它与调度相关的操作(如暂停 Trigger)。但是,Scheduler 只有在调用 start()方法后,才会真正地触发 trigger(即执行 job)
maven 坐标 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.quartz-scheduler</groupId > <artifactId > quartz</artifactId > <version > 2.2.1</version > </dependency > <dependency > <groupId > org.quartz-scheduler</groupId > <artifactId > quartz-jobs</artifactId > <version > 2.2.1</version > </dependency >
二、Quartz 入门案例 1、创建 QuartzTest 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import org.quartz.*;import org.quartz.impl.StdSchedulerFactory;public class QuartzTest { public static void main (String[] args) { try { JobDetail jobDetail = JobBuilder.newJob(HelloQuartz.class) .withIdentity("SendMessageJbo1" , "SendMessageGroup1" ) .usingJobData("name" , "ZhangSan" ) .build(); Trigger trigger = TriggerBuilder.newTrigger().withIdentity("SendMessageTrigger1" , "SendMessageTriggerGroup1" ) .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1 ) .repeatForever()).build(); Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.scheduleJob(jobDetail, trigger); scheduler.start(); try { Thread.sleep(8000 ); } catch (InterruptedException e) { e.printStackTrace(); } scheduler.shutdown(); } catch (Exception e) { e.printStackTrace(); } } }
2、创建 HelloQuartz 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import org.quartz.Job;import org.quartz.JobDetail;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import java.util.Date;public class HelloQuartz implements Job { @Override public void execute (JobExecutionContext context) throws JobExecutionException { JobDetail detail = context.getJobDetail(); String name = detail.getJobDataMap().getString("name" ); System.out.println("my job name is " + name + " at " + new Date()); } }
三、spring 整合 Quartz 创建 maven 工程 quartzdemo,打包方式为 war,导入 jar 包 自定义一个 Job 提供 Spring 配置文件 application-jobs.xml,配置自定义 Job、任务描述、触发器、调度工厂等 web.xml 中定义 启动 tomcat 完成测试 pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <packaging > war</packaging > <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context-support</artifactId > <version > 5.0.2.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-tx</artifactId > <version > 5.0.2.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-web</artifactId > <version > 5.0.2.RELEASE</version > </dependency > <dependency > <groupId > org.quartz-scheduler</groupId > <artifactId > quartz</artifactId > <version > 2.2.1</version > </dependency > <dependency > <groupId > org.quartz-scheduler</groupId > <artifactId > quartz-jobs</artifactId > <version > 2.2.1</version > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.apache.tomcat.maven</groupId > <artifactId > tomcat7-maven-plugin</artifactId > <configuration > <port > 8080</port > <path > /</path > </configuration > </plugin > </plugins > </build >
测试用 Job 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.atguigu;import java.util.Date;public class JobDemo { public void run () { System.out.println(new Date()); } }
application-jobs.xml Spring 配置文件:在 application-jobs.xml 中配置自定义 Job、任务描述、触发器、调度工厂等
创建 JobDetail 对象,作用是负责通过反射调用指定的 Job,注入目标对象,注入目标方法 注册一个触发器,指定任务触发的时间 注册一个统一的调度工厂,通过这个调度工厂调度任务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="jobDemo" class ="com.atguigu.JobDemo" > </bean > <bean id ="jobDetail" class ="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" > <property name ="targetObject" ref ="jobDemo" /> <property name ="targetMethod" value ="run" /> </bean > <bean id ="myTrigger" class ="org.springframework.scheduling.quartz.CronTriggerFactoryBean" > <property name ="jobDetail" ref ="jobDetail" /> <property name ="cronExpression" > <value > 0/10 * * * * ?</value > </property > </bean > <bean id ="scheduler" class ="org.springframework.scheduling.quartz.SchedulerFactoryBean" > <property name ="triggers" > <list > <ref bean ="myTrigger" /> </list > </property > </bean > </beans >
web.xml 启动 web,加载 spring 容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id ="WebApp_ID" version ="3.0" > <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > <context-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:application-jobs.xml</param-value > </context-param > </web-app >
启动 tomcat 控制台查看打印效果
Mon May 31 18:46:20 CST 2021 Mon May 31 18:46:30 CST 2021 Mon May 31 18:46:40 CST 2021 Mon May 31 18:46:50 CST 2021 Mon May 31 18:47:00 CST 2021 Mon May 31 18:47:10 CST 2021 Mon May 31 18:47:20 CST 2021
四、cron 表达式 Cron 表达式是一个字符串,字符串以 5 或 6 个空格隔开,分为 6 或 7 个域(年可选),每一个域代表一个含义
字段 允许值 允许的特殊字符 秒(Seconds) 0~59 的整数 , - * / 四个字符分(Minutes) 0~59 的整数 , - * / 四个字符小时(Hours) 0~23 的整数 , - * / 四个字符日期(DayofMonth) 1~31 的整数(需要考虑当月的天数) , - * ? / L W C 八个字符月份(Month) 1~12 的整数或者 JAN-DEC , - * / 四个字符星期(DayofWeek) 1~7 的整数或者 SUN-SAT (1=SUN) , - * ? / L C # 八个字符年(Year,可选) 1970~2099 , - * / 四个字符
逗号(,):指定一个值列表,例如使用在月域上 1,4,5,7 表示 1 月、4 月、5 月和 7 月
横杠(-):指定一个范围,例如在时域上 3-6 表示 3 点到 6 点(即 3 点、4 点、5 点、6 点)
星号(*):表示这个域上包含所有合法的值。例如,在月份域上使用星号意味着每个月都会触发
斜线(/):表示递增,例如使用在秒域上 0/15 表示每 15 秒
问号(?):只能用在日和周域上,但是不能在这两个域上同时使用。表示不指定,例如想在每月的 20 日触发调度,不管 20 日到底是星期几,则只能使用如下写法: 13 13 15 20 _ ?, 其中最后一位只能用?,而不能使用 _,如果使用 * 表示不管星期几都会触发,实际上并不是这样。
井号(#):只能使用在周域上,用于指定月份中的第几周的哪一天,例如 6#3,意思是某月的第三个周五 (6=星期五,3 意味着月份中的第三周)
L:某域上允许的最后一个值。只能使用在日和周域上。当用在日域上,表示的是在月域上指定的月份的最后一天。用于周域上时,表示周的最后一天,就是星期六
W:W 字符代表着工作日 (星期一到星期五),只能用在日域上,它用来指定离指定日的最近的一个工作日