Quartz最重要的3个基本要素:
也就是弄好这三个就可以了,一个调度器,一个任务,一个触发器,最后把任务跟触发器放到调度器里面执行就可以了
话不多说,直接先演示一个简单的栗子
前提:创建一个spring boot项目,层级结构如下
1、创建一个job类,实现Job接口,里面是具体要执行的任务
package com.cjw.sbptquartz.myJob;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class ChapterJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("我在工作········");
}
}
2、执行6个步骤开始任务
package com.cjw.sbptquartz.service.impl;
import com.cjw.sbptquartz.mapper.QuartzMapper;
import com.cjw.sbptquartz.model.EduChapter;
import com.cjw.sbptquartz.myJob.ChapterJob;
import com.cjw.sbptquartz.service.QuartzService;
import com.cjw.sbptquartz.utils.QuartzManager;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
@Service
public class QuartzServiceImpl implements QuartzService {
@Autowired
private QuartzManager quartzManager;
@Override
public void quartzTest() {
try {
//1、先实例化调度器工厂
SchedulerFactory factory = new StdSchedulerFactory();
//2、得到调度器
Scheduler scheduler = factory.getScheduler();
//3、创建任务
JobDetail jobDetail = newJob(ChapterJob.class)
.withDescription("这是我第一个任务")
.withIdentity("a", "b")//定义name/group,区分每个job
.build();
//4.创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withDescription("触发器")
.withIdentity("b", "c")
.startAt(new Date())
.withSchedule(
simpleSchedule()
.withIntervalInSeconds(1) //间隔1秒
.repeatForever() //一直循环
)
.build();
//5.将触发器和任务绑定到调度器中去
scheduler.scheduleJob(jobDetail, trigger);
//6.启动调度器
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
} finally {
}
}
}
JobDetail和Trigger都可以定义自己的一些map数据集合,在job中可以拿到。
在上面的QuartzServiceImpl类中稍微加一点
//3、创建任务
JobDetail jobDetail = newJob(ChapterJob.class)
.withDescription("这是我第一个任务")
.withIdentity("a", "b")//定义name/group,区分每个job
.usingJobData("nameJob", "王阿姨")//定义属性,传参到job中
.build();
//4.创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withDescription("大扫除触发器")
.withIdentity("b", "c")
.usingJobData("nameTri","嗯嗯")//定义属性,传参到job中
.startAt(new Date())
.withSchedule(
simpleSchedule()
.withIntervalInSeconds(1)
.repeatForever()
)
.build();
在上面的ChapterJob类中稍微加一点
package com.zte.sbptquartz.myJob;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class ChapterJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// Object name = jobExecutionContext.getJobDetail().getJobDataMap().get("name");
// Object name1 = jobExecutionContext.getJobDetail().getJobDataMap().get("a");
// System.out.println("name======="+name);
// System.out.println("a======="+name1);
System.out.println("我在工作········");
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); //jobDetail的
JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();//trigger的
//还可以两个map数据集合并,但是如果有相同的会被覆盖
JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
String nameJob = jobDataMap.getString("nameJob");//王阿姨
String nameTri = triggerDataMap.getString("nameTri");//嗯嗯
String nameJob1 = mergedJobDataMap.getString("nameJob");//王阿姨
System.out.println(nameJob);
System.out.println(nameTri);
System.out.println(nameJob1);
}
}
String nameJob = jobDataMap.getString(“nameJob”);//王阿姨
String nameTri= triggerDataMap.getString(“nameTri”);//嗯嗯
String nameJob1 = mergedJobDataMap.getString(“nameJob”);//王阿姨
如果每个值都要这么取会比较麻烦,还有一种办法,定义name属性实现set方法,框架会自动装进去
package com.zte.sbptquartz.myJob;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class ChapterJob implements Job {
private String nameJob;
private String nameTri;
public void setNameJob(String nameJob) {
this.nameJob = nameJob;
}
public void setNameTri(String nameTri) {
this.nameTri = nameTri;
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("我在工作········");
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); //jobDetail的
JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();//trigger的
//还可以两个map数据集合并,但是如果有相同的会被覆盖
JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
// String nameJob = jobDataMap.getString("nameJob");//王阿姨
// String nameTri = triggerDataMap.getString("nameTri");//嗯嗯
// String nameJob1 = mergedJobDataMap.getString("nameJob");//王阿姨
System.out.println(nameJob);
System.out.println(nameTri);
}
}
//3、创建任务
JobDetail jobDetail = newJob(ChapterJob.class)
.withDescription("这是我第一个任务")
.withIdentity("a", "b")//定义name/group,区分每个job
.usingJobData("nameJob", "王阿姨")//定义属性,传参到job中
.build();
在循环执行任务的过程中,每次执行一次任务JobDetail都是一个新的实例,这样做的目的是防止并发访问。
但是有些业务是需要控制下一次执行的开始是上一次执行的结束,好办,加个注解,禁止并发执行。
@DisallowConcurrentExecution
public class ChapterJob implements Job {
还有一个注解了解一下
@PersistJobDataAfterExecution:告诉Quartz在成功执行了Job实现类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据,使得该JobDetail实例在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。
触发器有 SimpleTrigger 和 CronTrigger,上面用的就是SimpleTrigger
simpleTrigger触发器是为那种需要在特定日期/时间启动,且以一个可能的间隔时间重复执行N次的Job所设计的。
cronTrigger触发器可以像日历那样按日程触发任务,是一个基于日历的作业调度器,它有Cron表达式:用来配置CronTrigger实例,由7个部分组成,每个部分就如图所示分别对应秒 分 一直到年。(表达式生成的网站https://qqe2.com/cron)
SimpleTrigger 实例:
//4.创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withDescription("大扫除触发器")
.withIdentity("b", "c")
.usingJobData("nameTri","嗯嗯")
.startAt(new Date())
.startNow()//一旦加入scheduler,立即生效
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)//一秒一次
.withIntervalInHours(1)//一小时一次
// .repeatForever() //一直重复
.withRepeatCount(2)//重复几次
)
.build();
CronTrigger实例:
//触发器(Trigger)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") //定义该触发器的唯一标识
.startAt(new Date()) //开始时间
.startNow()//一旦加入scheduler,立即生效
.withSchedule(CronScheduleBuilder.cronSchedule("30 * * * * ?"))//CronTrigger 在此定义表达式:每分钟的第30秒触发一次
.WithCronSchedule("0 0/30 8-20 * * ?")//每天8-20点,每半个小时执行一次(即8:00、8:30 。。。。 19:30、20:30)
.WithCronSchedule("0 0 2 ? * Mon-Fri")//每个工作日的凌晨2点执行1次
.WithCronSchedule("0 0 2 ? * Mon,Wes")//每个周的周一和周四的2点执行1次
.build();
为了方便管理,可以弄成一个定时器管理类
package com.zte.sbptquartz.utils;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 定时器管理
*/
public class QuartzManager {
private static Logger logger = LoggerFactory.getLogger(QuartzManager.class);
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
/**
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param cron 时间设置,参考quartz说明文档
* @Description: 添加一个定时任务
*/
public static void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class jobClass, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
* @Description: 修改一个任务的触发时间
*/
public static void modifyJobTime(String triggerName, String triggerGroupName, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
//JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
//Class extends Job> jobClass = jobDetail.getJobClass();
//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
* @Description: 移除一个任务
*/
public static void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public static void shutdownJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 安全关闭
*
* @throws SchedulerException
*/
public static void safeShutdown() throws SchedulerException {
Scheduler scheduler = schedulerFactory.getScheduler();
int executingJobSize = scheduler.getCurrentlyExecutingJobs().size();
logger.info("安全关闭 当前还有" + executingJobSize + "个任务正在执行,等待完成后关闭");
//等待任务执行完后安全关闭
scheduler.shutdown(true);
logger.info("安全关闭 成功");
}
}
示范
public void testGetJobState(){
try {
QuartzManager.addJob("jobnamee1","jobgroupp1",
"trinamee1","trigroupp1",
ChapterJob1.class,"0/1 * * * * ? *");//这行代码就已经启动了定时器,每秒执行一次
//cron表达式可以去https://qqe2.com/cron生成
QuartzManager1.removeJob("jobnamee","jobgroupp",
"trinamee","trigroupp");//移除任务
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}