Quartz框架(一)—Quartz的基本配置
Quartz框架(二)—jobstore数据库表字段详解
Quartz框架(三)—任务的并行/串行执行
Quartz框架(四)—misfire处理机制
Quartz框架(五)— 有状态的job和无状态job
Quartz框架(六)— Trigger状态转换
Quartz框架(七)— Quartz集群原理
Quartz框架(八)— Quartz实现异步通知
Quartz框架(九)— 动态操作Quartz定时任务
Quartz框架(十)监听
1. 如何创建一个任务
方法一:JobDetailFactoryBean或者CronTriggerFactoryBean
如何创建一个复杂的Bean对象,我们可以借助FactoryBean。而巧妙的是,JobDetailFactoryBean或者CronTriggerFactoryBean都实现了FactoryBean接口和InitializingBean接口。虽然我们new JobDetailFactoryBean(),但是实际上是将JobDetail交由的IOC管理。而InitializingBean接口会在属性装载完毕之后,自动的回调afterPropertiesSet()
方法,完成Bean对象的最终构建:
@Bean
public JobDetailFactoryBean jobDetail(){
//查询数据库或者配置文件
JobDetailFactoryBean jobDetailFactoryBean=new JobDetailFactoryBean();
jobDetailFactoryBean.setName("");
jobDetailFactoryBean.setBeanName("");
jobDetailFactoryBean.setJobClass((Class extends Job>) aClass);
jobDetailFactoryBean.setGroup("");
jobDetailFactoryBean.setDurability(true);
return jobDetailFactoryBean;
}
而实际上更加直观的写法:
JobDetailFactoryBean jobFactory = new JobDetailFactoryBean();
jobFactory.setName("");
jobFactory.setBeanName("");
jobFactory.setJobClass((Class extends Job>) aClass);
jobFactory.setGroup("");
jobFactory.setDurability(true);
jobFactory.afterPropertiesSet();
//完成JobDetail的创建
JobDetail jobDetail= jobFactory.getObject();
方法二:使用建筑者模式创建Job或者Trigger
这种方式是通过建筑者模式创建Job或者Trigger。也是更加的优雅。
//创建Job
public static JobDetail getJobDetail(JobKey jobKey, String description, boolean jobShouldRecover, JobDataMap jobDataMap, Class extends Job> jobClass) {
return JobBuilder.newJob(jobClass)
.withIdentity(jobKey)
.withDescription(description)
.setJobData(jobDataMap)
.usingJobData(jobDataMap) //设置JobDataMap字段
.requestRecovery(jobShouldRecover)
.storeDurably() //表示当没有触发器与之关联时,仍然将job继续保存在Scheduler中
.build();
}
//创建Trigger
public static Trigger getCornTrigger(TriggerKey triggerKey, String description, JobDataMap jobDataMap, String cronExpression, JobKey jobKey) {
return TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.withDescription(description)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.forJob(jobKey.getName(), jobKey.getGroup()) //制定Trigger和Job的关联关系
.usingJobData(jobDataMap) //具体执行的方法中可以拿到这个传进去的信息。
.build();
}
2. 任务的动态操作
首先我们需要在项目启动时Spring容器启动完毕,去加载自定义定时配置表的配置,动态的去创建任务。那么需要实现CommandLineRunner/ApplicationRunner
接口。
SpringBoot启动时初始化方法集合
实际上,动态操作定时任务,本质上就是操作scheduler(调度器)中的内容,所以实际上便是直接调用org.quartz.Scheduler
类。然后根据自身业务进行扩展,代码就在附录中。
3. 注意事项
JobDataMap在Job和Trigger存储的数据并不一致。
@Slf4j
public class TestJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
log.info("Job中的JobDataMap"+JSONObject.toJSONString(jobDataMap));
JobDataMap jobDataMap1 = context.getTrigger().getJobDataMap();
log.info("Trigger中的JobDataMap"+JSONObject.toJSONString(jobDataMap1));
log.info("【定时任务测试--开始】");
}
}
若是我们调用org.quartz.Scheduler
中的triggerJob
方法,立即执行一次定时任务,并且传入了JobDataMap,实际上context.getTrigger().getJobDataMap();
才可以获取到。
void triggerJob(JobKey jobKey, JobDataMap data)
throws SchedulerException;
附录
动态操作定时的完整代码:
/**
* Created by EalenXie on 2019/7/10 13:49.
* 核心其实就是Scheduler的功能 , 这里只是非常简单的示例说明其功能
* 如需根据自身业务进行扩展 请参考 {@link org.quartz.Scheduler}
*/
@Slf4j
@Service
public class QuartzJobService {
//Quartz定时任务核心的功能实现类
private Scheduler scheduler;
public QuartzJobService(@Autowired SchedulerFactoryBean schedulerFactoryBean) {
scheduler = schedulerFactoryBean.getScheduler();
}
/**
* 创建和启动 定时任务
* {@link org.quartz.Scheduler#scheduleJob(JobDetail, Trigger)}
*
* @param define 定时任务
*/
public void scheduleJob(TaskDefine define) throws SchedulerException {
//1.定时任务 的 名字和组名
JobKey jobKey = define.getJobKey();
//2.定时任务 的 元数据
JobDataMap jobDataMap = getJobDataMap(define.getJobDataMap());
//3.定时任务 的 描述
String description = define.getDescription();
//4.定时任务 的 逻辑实现类
Class extends Job> jobClass = define.getJobClass();
//5.定时任务 的 cron表达式
String cron = define.getCronExpression();
JobDetail jobDetail = getJobDetail(jobKey, description, jobDataMap, jobClass);
Trigger trigger = getTrigger(jobKey, description, jobDataMap, cron);
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 暂停Job
* {@link org.quartz.Scheduler#pauseJob(JobKey)}
*/
public void pauseJob(JobKey jobKey) throws SchedulerException {
scheduler.pauseJob(jobKey);
}
/**
* 恢复Job
* {@link org.quartz.Scheduler#resumeJob(JobKey)}
*/
public void resumeJob(JobKey jobKey) throws SchedulerException {
scheduler.resumeJob(jobKey);
}
/**
* 删除Job
* {@link org.quartz.Scheduler#deleteJob(JobKey)}
*/
public void deleteJob(JobKey jobKey) throws SchedulerException {
scheduler.deleteJob(jobKey);
}
/**
* 修改Job 的cron表达式
*/
public boolean modifyJobCron(TaskDefine define) {
String cronExpression = define.getCronExpression();
//1.如果cron表达式的格式不正确,则返回修改失败
if (!CronExpression.isValidExpression(cronExpression)) return false;
JobKey jobKey = define.getJobKey();
TriggerKey triggerKey = new TriggerKey(jobKey.getName(), jobKey.getGroup());
try {
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
JobDataMap jobDataMap = getJobDataMap(define.getJobDataMap());
//2.如果cron发生变化了,则按新cron触发 进行重新启动定时任务
if (!cronTrigger.getCronExpression().equalsIgnoreCase(cronExpression)) {
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.usingJobData(jobDataMap)
.build();
scheduler.rescheduleJob(triggerKey, trigger);
}
} catch (SchedulerException e) {
log.error("printStackTrace", e);
return false;
}
return true;
}
/**
* 获取定时任务的定义
* JobDetail是任务的定义,Job是任务的执行逻辑
*
* @param jobKey 定时任务的名称 组名
* @param description 定时任务的 描述
* @param jobDataMap 定时任务的 元数据
* @param jobClass {@link org.quartz.Job} 定时任务的 真正执行逻辑定义类
*/
public JobDetail getJobDetail(JobKey jobKey, String description, JobDataMap jobDataMap, Class extends Job> jobClass) {
return JobBuilder.newJob(jobClass)
.withIdentity(jobKey)
.withDescription(description)
.setJobData(jobDataMap)
.usingJobData(jobDataMap)
.requestRecovery()
.storeDurably()
.build();
}
/**
* 获取Trigger (Job的触发器,执行规则)
*
* @param jobKey 定时任务的名称 组名
* @param description 定时任务的 描述
* @param jobDataMap 定时任务的 元数据
* @param cronExpression 定时任务的 执行cron表达式
*/
public Trigger getTrigger(JobKey jobKey, String description, JobDataMap jobDataMap, String cronExpression) {
return TriggerBuilder.newTrigger()
.withIdentity(jobKey.getName(), jobKey.getGroup())
.withDescription(description)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.usingJobData(jobDataMap)
.build();
}
public JobDataMap getJobDataMap(Map, ?> map) {
return map == null ? new JobDataMap() : new JobDataMap(map);
}
}
文章参考
《SpringBoot整合Quartz作为调度中心使用完整实例》