1.导入依赖
所需maven依赖如下
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
</dependency>
2.编码开始
①任务执行类
定时任务需要有一个具体实现业务逻辑的类,以供调度器去定时执行。该类需要实现框架中的 Job 接口,并实现方法
代码如下:
package com.springcloud.timer;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* //进行具体业务逻辑编写
*/
public class TestTimerDemo implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//获取到主函数中传递来的jobDetail
JobDetail jobDetail = context.getJobDetail();
//获取到jobDetail中传递来的参数
String name = jobDetail.getJobDataMap().getString("name");
String age = jobDetail.getJobDataMap().getString("age");
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(date);
System.out.println("My name is " + name + ",And my age is " + age + " now time is " + format);
}
}
②.主函数构造
1.Cron表达式
定时任务的基础,用于决定定时规则。具体编写规则参考文章
cron表达式
还需要交给构造器来构造。
代码如下:
//1.定义cron表达式,每30秒执行一次
String cronExpression = "0/30 * * * * ?";
//构造出cron任务器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
2.定义jobDetail
将上面定义的执行类引入主文件中,并且可以向执行类转递参数,以及对其命名。
代码如下:
//2.首先定义jobDetail
JobDetail jobDetail = JobBuilder.newJob(TestTimerDemo.class)
//定义该任务执行类 的名字跟组
.withIdentity("jobName", "groupName")
//传递参数用,键值对方式
.usingJobData("name", "jobDetail 1")
.usingJobData("age", "25")
//创建出来
.build();
3.触发器Trigger
决定任务何时触发,与Cron表达式一起使用。
代码如下:
//3.定义一个触发器,进行任务定时规则的确立
CronTrigger trigger = TriggerBuilder.newTrigger()
//触发器名字跟所属组名称
.withIdentity("triggerName", "groupName")
//进行定时
.withSchedule(cronScheduleBuilder)
//表示加入scheduler后立刻执行
.startNow()
.build();
4.任务调度器scheduler
所有上述组件交由任务调度器进行触发执行,统一调度。
代码如下:
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//组件填充
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
5.完整主函数
package com.springcloud.timer;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class quartzMain {
public static void main(String[] args) {
//1.定义cron表达式,每30秒执行一次
String cronExpression = "0/30 * * * * ?";
//构造出cron任务器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//2.首先定义jobDetail
JobDetail jobDetail = JobBuilder.newJob(TestTimerDemo.class)
//定义该任务执行类 的名字跟组
.withIdentity("jobName", "groupName")
//传递参数用,键值对方式
.usingJobData("name", "jobDetail 1")
.usingJobData("age", "25")
//创建出来
.build();
//3.定义一个触发器,进行任务定时规则的确立
CronTrigger trigger = TriggerBuilder.newTrigger()
//触发器名字跟所属组名称
.withIdentity("triggerName", "groupName")
//进行定时
.withSchedule(cronScheduleBuilder)
//表示加入scheduler后立刻执行
.startNow()
.build();
//4.创建任务调度器scheduler
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//组件填充
scheduler.scheduleJob(jobDetail, trigger);
//不添加该语句,任务不会执行
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
实际业务中,用到的参数都可以通过接口参数传入。
③执行效果
-----整合spring boot2框架实现增删启停
1.导入框架启动器依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2.配置yml文件
server:
port: 7002
spring:
quartz:
#以数据库方式存储(用在分库存定时器数据的时候)
job-store-type: jdbc
jdbc:
initialize-schema: embedded
#设置自动启动,默认为 true
auto-startup: true
#启动时更新己存在的Job
overwrite-existing-jobs: true
#相关属性配置
properties:
org:
quartz:
scheduler:
#调度标识名,集群中每一个实例都必须使用相同的名称
instanceName: DefaultQuartzScheduler
#ID设置为自动获取,每一个必须不同
instanceId: AUTO
jobStore:
#数据保存方式为数据库持久化
class: org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库代理类,一般这个已经可以满足大部分数据库
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#表的前缀,默认是QRTZ_
tablePrefix: QRTZ_
#是否加入集群
isClustered: false
#调度实例失效的检查时间间隔
clusterCheckinInterval: 10000
#JobDataMaps是否限制为只能存Sring类型,默认为false
useProperties: true
# #是否使用JDBC托管
# txIsolationLevelReadCommitted: true
threadPool:
#线程池的实现类(一般SimpleThreadPool即可满足几乎全部需求)
class: org.quartz.simpl.SimpleThreadPool
#指定线程数,一般设置为1-100之间的整数,根据系统资源配置
threadCount: 10
#设置线程的优先级
threadPriority: 5
#表明Quartz产生的线程是否继承初始化Quartz实例的线程的上下文类加载器
threadsInheritContextClassLoaderOfInitializingThread: true
3.编写执行类
执行类 demo1
package com.springcloud.timer;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 进行具体业务逻辑编写
*/
//注解将JobDataMap持久化保存,这样在每次执行生成新对象的时候,还是可以获取到原来的数据,常用的是计算执行了多少次
@PersistJobDataAfterExecution
public class TestTimerDemo implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//获取到主函数中传递来的jobDetail
JobDetail jobDetail = context.getJobDetail();
//获取到jobDetail中传递来的参数
String name = jobDetail.getJobDataMap().getString("name");
String age = jobDetail.getJobDataMap().getString("age");
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(date);
System.out.println("NUM:001 => My name is " + name + ",age is " + age + " now time is " + format);
}
}
执行类demo2
package com.springcloud.timer;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 进行具体业务逻辑编写
*/
public class TestTimerDemo2 implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//获取到主函数中传递来的jobDetail
JobDetail jobDetail = context.getJobDetail();
//获取到jobDetail中传递来的参数
String name = jobDetail.getJobDataMap().getString("name");
String age = jobDetail.getJobDataMap().getString("age");
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(date);
System.out.println("NUM:002 => My name is " + name + ",age is " + age + " now time is " + format);
}
}
4.实体类
package com.springcloud.domain;
import lombok.Data;
@Data
public class SysJob {
/**
* Cron表达式
*/
private String cron;
/**
* 任务名称(不允许重复)
*/
private String jobName;
/**
* 任务组名
*/
private String groupName;
/**
* 新任务名(需要修改的任务名)
*/
private String newJobName;
/**
* 新任务组名(需要修改的组名)
*/
private String newGroupName;
/**
* 触发器名
*/
private String triggerName;
/**
* 触发器组命
*/
private String triggerGroupName;
// /**
// * 新触发器名
// */
// private String newTriggerName;
// /**
// * 新触发器组命
// */
// private String newTriggerGroupName;
}
5.controller层构造
代码如下:
package com.springcloud.controller;
import com.springcloud.domain.SysJob;
import com.springcloud.timer.TestTimerDemo;
import com.springcloud.timer.TestTimerDemo2;
import org.quartz.*;
import org.quartz.spi.MutableTrigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@RequestMapping("/timer")
@RestController
public class TimerController {
@Autowired
private Scheduler scheduler;
/**
* 添加定时器
*/
@PostMapping("/add")
public void add(@RequestBody SysJob sysJob) throws SchedulerException {
if (sysJob.getCron() == null) {
sysJob.setCron("0/10 * * * * ?");
}
//构造出cron任务器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysJob.getCron());
//2.首先定义jobDetail
JobDetail jobDetail = JobBuilder.newJob(TestTimerDemo.class)
//定义该任务执行类 的名字跟组
.withIdentity(sysJob.getJobName(), sysJob.getGroupName())
//传递参数用,键值对方式
.usingJobData("name", sysJob.getJobName())
.usingJobData("age", "25")
//创建出来
.build();
//3.定义一个触发器,进行任务定时规则的确立
CronTrigger trigger = TriggerBuilder.newTrigger()
//触发器名字跟所属组名称
.withIdentity(sysJob.getTriggerName(), sysJob.getTriggerGroupName())
//进行定时
.withSchedule(cronScheduleBuilder)
//表示加入scheduler后立刻执行
.startNow()
.build();
//4.交由scheduler执行
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("定时任务开始。。");
}
/**
* 暂停定时任务
*
* @throws SchedulerException
*/
@PostMapping("/pause")
public void pause(@RequestBody SysJob sysJob) throws SchedulerException {
//获取job的唯一标识key
JobKey jobKey = JobKey.jobKey(sysJob.getJobName(), sysJob.getGroupName());
scheduler.pauseJob(jobKey);
System.out.println("暂停定时任务");
}
/**
* 恢复定时任务
*
* @throws SchedulerException
*/
@PostMapping("/resume")
public void resume(@RequestBody SysJob sysJob) throws SchedulerException {
//获取job的唯一标识key
JobKey jobKey = JobKey.jobKey(sysJob.getJobName(), sysJob.getGroupName());
scheduler.resumeJob(jobKey);
System.out.println("定时任务恢复");
}
/**
* 修改定时任务时间(直接修改时间,不改执行任务)
* 不动任务,只动触发器,封装方法使用 scheduler.rescheduleJob();
*/
@PostMapping("/edit")
public void edit(@RequestBody SysJob sysJob) throws SchedulerException {
//新的cron表达式
String newCron = sysJob.getCron();
if (newCron==null){
newCron="0/15 * * * * ?";
}
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(newCron);
//修改触发器构造
//获取原本触发器的唯一标识
TriggerKey oldTriggerKey = TriggerKey.triggerKey(sysJob.getTriggerName(), sysJob.getTriggerGroupName());
//给原本的触发器赋予新的触发器cron表达
CronTrigger newTrigger = TriggerBuilder.newTrigger()
.withIdentity(oldTriggerKey)
.withSchedule(cronScheduleBuilder).build();
//交由scheduler进行修改
scheduler.rescheduleJob(oldTriggerKey, newTrigger);
System.out.println("定时任务时间改变");
}
/**
* 完全修改定时任务时间(直接修改时间,同时修改执行任务)
* 删除原来的任务,再次构造新的任务、触发器,再交由调度器执行
*/
@PostMapping("/editWhole")
public void editWhole(@RequestBody SysJob sysJob) throws SchedulerException {
//获取job的唯一标识key
JobKey OldJobKey = JobKey.jobKey(sysJob.getJobName(), sysJob.getGroupName());
//删除任务(相关的触发器也一同删除)
scheduler.deleteJob(OldJobKey);
String newCron = sysJob.getCron();
if (newCron==null){
newCron="0/5 * * * * ?";
}
//构造出cron任务器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(newCron);
//2.定义新的jobDetail
JobDetail jobDetail = JobBuilder.newJob(TestTimerDemo2.class)
//定义新任务执行类 的新名字跟新组
.withIdentity(sysJob.getNewJobName(), sysJob.getNewGroupName())
//传递参数用,键值对方式
.usingJobData("name", sysJob.getNewJobName())
.usingJobData("age", "115")
//创建出来
.build();
//3.定义一个新的触发器,进行任务定时规则的确立
CronTrigger trigger = TriggerBuilder.newTrigger()
//触发器名字跟所属组名称
.withIdentity(sysJob.getTriggerName(), sysJob.getTriggerGroupName())
//进行定时
.withSchedule(cronScheduleBuilder)
//表示加入scheduler后立刻执行
.startNow()
.build();
//4.交由scheduler执行
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("定时任务整体改变");
}
/**
* 移除定时器
*/
@PostMapping("/remove")
public void remove(@RequestBody SysJob sysJob) throws SchedulerException {
//获取触发器的唯一标识key
TriggerKey triggerKey = TriggerKey.triggerKey(sysJob.getTriggerName(), sysJob.getTriggerGroupName());
//停止触发器
scheduler.pauseTrigger(triggerKey);
//移除触发器
scheduler.unscheduleJob(triggerKey);
//获取job的唯一标识key
JobKey jobKey = JobKey.jobKey(sysJob.getJobName(), sysJob.getGroupName());
//删除任务
scheduler.deleteJob(jobKey);
System.out.println("移除定时器");
}
}
6.请求及执行结果
①添加
请求方式
运行结果
②暂停
请求方式
执行结果
③恢复
请求方式
执行结果
④改变定时时间
请求方式
执行结果
⑤改变整体(包括执行任务)
请求方式
在此任务名也可以用老名称,但是为了展示,使用新名。
执行结果
⑥移除定时任务
请求方式
执行结果
7.备注
a.可以跟数据库做关联,将每条定时器任务参数持久化保存。
b.任务执行类,现在是写死在程序中,如果需要动态选择,就可以使用
Class.forName("com.springcloud.timer.TestTimerDemo");
语句来进行替换,括号内填入执行类的全类名,与原来的进行交换。
c.如果需要计算执行了几次,就在执行类上加注解,并把值加一再存进去。
代码如下:
package com.springcloud.timer;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 进行具体业务逻辑编写
*/
//注解将JobDataMap持久化保存,这样在每次执行生成新对象的时候,还是可以获取到原来的数据,常用的是计算执行了多少次
@PersistJobDataAfterExecution
public class TestTimerDemo implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//获取到主函数中传递来的jobDetail
JobDetail jobDetail = context.getJobDetail();
//获取到jobDetail中传递来的参数
String name = jobDetail.getJobDataMap().getString("name");
String age = jobDetail.getJobDataMap().getString("age");
int count = jobDetail.getJobDataMap().getInt("count");
count=count+1;
//不存回去就没有办法计数
jobDetail.getJobDataMap().put("count",count);
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(date);
System.out.println("NUM:001 => My name is " + name + ",age is " + age + " now time is " + format);
System.out.println(count);
}
}
执行结果:
8 持久化到数据库
需要在数据库新建11张表,具体表的情况可以上网搜索,表含义参考
Quarzt表含义
一些表的创建语句
tips:
定时器启动、暂停 数据库中的数据区别
qrtz_triggers
表
TRIGGER_STATE 字段
启动 :WAITING
暂停:PAUSED