先上依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
新建一个自己的Job
类,待会触发器执行的就是这个类重写的QuartzJobBean
下的executeInternal
方法
里面可以通过spring注入业务类,这样就可以执行业务逻辑了
package com.fchan.layui.quzrtzForSpring;
import com.fchan.layui.quartz.TestJobDetailService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
@Component
public class HiJob extends QuartzJobBean {
//自己的业务类,我在里面就打印输出了一下字符串:"开始处理业务了"
@Autowired
private TestJobDetailService testJobDetailService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
testJobDetailService.doJob();
System.out.println(" Hi! :" + context.getJobDetail().getKey());
}
}
配置类,配置Jobdetail(配置执行哪个Job)和Trigger触发器(定义cron的bean)
Jobdetail->Job->业务类
package com.fchan.layui.quzrtzForSpring;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuzrtzForSpringConfig {
@Bean
public JobDetail myJobDetail(){
JobDetail jobDetail = JobBuilder.newJob(HiJob.class)
//任务名和任务组别
.withIdentity("myJobName","myJobGroup")
//JobDataMap可以给任务execute传递参数
.usingJobData("job_param","job_param1")
.storeDurably()
.build();
return jobDetail;
}
@Bean
public Trigger myTrigger(){
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(myJobDetail())
//触发器名,触发器所在组
.withIdentity("myTrigger1","myTriggerGroup1")
.usingJobData("job_trigger_param","job_trigger_param1")
.startNow()
//.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever())
.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ? 2020"))
.build();
return trigger;
}
}
然后跑起来就可以在控制台看到业务类中打印输出的内容了
动态修改任务执行时间
动态执行的时候就不能直接写死时间了。
quzrtz中的定时任务分为这几大块:
- jobDetail:描述实际执行任务的class
- trigger:触发器,定义执行时间
- scheduler:关联触发器和任务
所以要动态修改时间,就要修改触发器中的时间,然后重新关联任务。
代码demo
实际执行任务class
package com.fchan.business.cron;
import com.fchan.business.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import javax.annotation.Resource;
import java.time.LocalDateTime;
@Slf4j
public class MailTask extends QuartzJobBean {
@Resource
ISysUserService iSysUserService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("开始执行邮件任务" + LocalDateTime.now());
}
}
package com.fchan.business.cron;
import lombok.Data;
/**
* 定义时间和实际执行任务的class
*/
@Data
public class QuartzBean {
/** 任务id */
private String id;
/** 任务名称 */
private String jobName;
/** 任务执行类 */
private String jobClass;
/** 任务状态 启动还是暂停*/
private Integer status;
/** 任务运行时间表达式 */
private String cronExpression;
}
新增/暂停/修改/删除定时任务
package com.fchan.business.utils;
import com.fchan.business.cron.QuartzBean;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;
@Slf4j
public class CronUtil {
/**
* 创建一个定时任务
* @param scheduler
* @param quartzBean
*/
public static void createScheduleJob(Scheduler scheduler, QuartzBean quartzBean){
try {
//反射获取实际执行任务的class
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
//构建任务信息,实际执行的任务类
JobDetail jobDetail = JobBuilder
.newJob(jobClass)
//jobName需要保证唯一
.withIdentity(quartzBean.getJobName())
.build();
//设置执行方式为cron
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
.cronSchedule(quartzBean.getCronExpression())
//阻塞的过期任务立即执行
.withMisfireHandlingInstructionFireAndProceed();
//关联触发器和cron执行器
CronTrigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity(quartzBean.getJobName())
.withSchedule(cronScheduleBuilder)
.build();
//检查任务是否过期
Date nextFireTime = cronTrigger.getFireTimeAfter(new Date());
if(Objects.isNull(nextFireTime)){
log.info("任务已过期,job:{}", quartzBean);
return;
}
//按照cron时间开始运行任务,并且时间已经过期则创建时会报错,提示过期
scheduler.scheduleJob(jobDetail, cronTrigger);
} catch (ClassNotFoundException | SchedulerException e) {
throw new RuntimeException(e);
}
}
/**
* 更新当前正在运行的任务的cron时间
* @param scheduler
* @param quartzBean
*/
public static void updateJobTime(Scheduler scheduler, QuartzBean quartzBean){
//build触发key
TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
String cronExpression = quartzBean.getCronExpression();
//build新的cron执行器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
try {
//获取当前正在运行的触发器
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if(Objects.isNull(cronTrigger)){
log.error("未找到触发器,jobName:{}", quartzBean.getJobName());
return;
}
//根据新的执行器重新关联触发器
cronTrigger = cronTrigger
.getTriggerBuilder()
.withIdentity(triggerKey)
.withSchedule(cronScheduleBuilder)
.build();
log.info("重置了任务时间" + LocalDateTime.now());
//重置对应的job
scheduler.rescheduleJob(triggerKey, cronTrigger);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
/**
* 暂停任务
* @param scheduler
* @param jobName
*/
public static void pauseJob(Scheduler scheduler, String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
/**
* 恢复暂停的任务
* @param scheduler
* @param jobName
*/
public static void resumeJob(Scheduler scheduler, String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
/**
* 删除任务
* @param scheduler
* @param jobName
*/
public static void deleteJob(Scheduler scheduler, String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.deleteJob(jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
}