Spring 整合 Quartz 实现动态定时任务
Quartz 基本概念及原理
作为一个优秀的开源调度框架,Quartz 具有以下特点:
1、强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
2、 灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;
3、分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。本文暂不讨论该部分内容。
作为 spring 默认的调度框架,Quartz 很容易与 Spring 集成实现灵活可配置的调度功能。
Quartz专用词汇:
1. scheduler :任务调度器
2. trigger :触发器,用于定义任务调度时间规则
3. job :任务,即被调度的任务 misfire :错过的,指本来应该被执行但实际没有被执行的任务调度
Quartz 核心元素关系图
job任务
package com.kaishengit;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyQuartzJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hi,Quartz!!!!!!!!!!!!!");
}
}
triger 触发器
package com.kaishengit;
import org.quartz.*;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Date;
import java.util.Timer;
public class Test {
public static void main(String[] args) throws SchedulerException {
/*Timer timer = new Timer();
timer.schedule(new MyTimerTask(),0,5000);*/
//任务
JobDetail jobDetail = JobBuilder.newJob(MyQuartzJob.class).build();
//创建触发器
/*SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
scheduleBuilder.withIntervalInSeconds(5);
scheduleBuilder.repeatForever();*/
// cron
ScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("1 35 14 5 8 ? 2016-2016");
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(scheduleBuilder).build();
//创建调度器
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.scheduleJob(jobDetail,trigger);
scheduler.start();
}
}
package com.toltech.phatent;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
/**
* QuartzCase
* @author Wgs
* @version 1.0
* @since 2017年8月26日下午2:45:55
*/
public class QuartzCase {
public static void main(String[] args) {
try {
JobDetail jobDetail = JobBuilder.newJob(TestJob.class) // 任务执行类
.withIdentity("job1_1", "jGroup1")// 任务名,任务组
.build();
Date date = new Date();
date = DateUtils.addMinutes(date, 1);
Trigger trigger =TriggerBuilder.newTrigger().withIdentity("trigger1","group1")
.startAt(date).build();
Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
while(true){
TriggerState state = scheduler.getTriggerState(trigger.getKey());
if(state == TriggerState.COMPLETE){
scheduler.pauseTrigger(trigger.getKey());// 停止触发器
scheduler.unscheduleJob(trigger.getKey());// 移除触发器
scheduler.deleteJob(trigger.getJobKey());
System.out.println("job cancel");
break;
}
Thread.sleep(3000L);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Spring 3 调度器示例 —— JDK 定时器和 Quartz 展示 【已翻译100%】
与spring结合
创建任务
package com.kaishengit;
import javax.inject.Named;
@Named
public class MySpringJob {
public void sayHello() {
System.out.println("Hello,Spring~~~~~~~~~~~~~~~~~~~~~");
}
}
applicationContext-quarz.xml
<?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">
<!--MySpringJob已经纳入spring管理了这边不用写-->
<!--JobDetail-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="mySpringJob"/>
<property name="targetMethod" value="sayHello"/>
</bean>
<!--触发器-->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="cronExpression" value="0/3 * * * * ?"/>
</bean>
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="trigger"/>
</list>
</property>
</bean>
</beans>
动态添加
动态添加
job包中的TaskRemindJob类
cron pom依赖时分秒转换成DateTime
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.cronutils</groupId>
<artifactId>cron-utils</artifactId>
<version>4.1.0</version>
</dependency>
job包中的TaskRemindJob类
package com.kaishengit.job;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class TaskRemindJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String title = (String) jobDataMap.get("context");
System.out.println("提醒内容:" + title);
}
}
package com.kaishengit.service;
import com.cronutils.builder.CronBuilder;
import com.cronutils.model.Cron;
import com.cronutils.model.CronType;
import static com.cronutils.model.field.expression.FieldExpressionFactory.*;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.field.expression.On;
import com.kaishengit.job.TaskRemindJob;
import com.kaishengit.mapper.TaskMapper;
import com.kaishengit.pojo.Task;
import com.kaishengit.util.ShiroUtil;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.List;
@Named
public class TaskService {
@Inject
private TaskMapper taskMapper;
@Inject
private SchedulerFactoryBean schedulerFactoryBean;
private Logger logger = LoggerFactory.getLogger(TaskService.class);
/**
* 添加待办任务
* @param task
* @param hour
* @param min
*/
public void saveTask(Task task, String hour, String min) {
if(StringUtils.isNotEmpty(hour) && StringUtils.isNotEmpty(min)) {
String reminderTime = task.getStart() + " "+hour + ":" + min + ":00";
logger.debug("提醒时间为{}" , reminderTime);
task.setRemindertime(reminderTime);
task.setUserid(ShiroUtil.getCurrentUserID());
taskMapper.save(task);
//TODO Quartz动态任务
//yyyy-MM-dd HH:mm:ss -> DateTime
DateTime dateTime = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime(reminderTime);
//datetime -> cron
Cron cron = CronBuilder.cron(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ))
.withYear(on(dateTime.getYear()))
.withMonth(on(dateTime.getMonthOfYear()))
.withDoM(on(dateTime.getDayOfMonth()))
.withHour(on(dateTime.getHourOfDay()))
.withMinute(on(dateTime.getMinuteOfHour()))
.withSecond(on(0))
.withDoW(questionMark()).instance();
String cronExpress = cron.asString();
logger.debug("CRON: {}",cronExpress);
JobDetail jobDetail = JobBuilder
.newJob(TaskRemindJob.class)
.usingJobData("context",task.getTitle())
.withIdentity("task:"+task.getId(),"task")
.build();
ScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpress);
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(scheduleBuilder).build();
Scheduler scheduler = schedulerFactoryBean.getScheduler();
try {
scheduler.scheduleJob(jobDetail,trigger);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
} else {
task.setUserid(ShiroUtil.getCurrentUserID());
taskMapper.save(task);
}
}
/**
* 获取当前用户的所有任务
* @return
*/
public List<Task> findTaskByUserId(String start,String end) {
return taskMapper.findByUserIdAndDateRanger(ShiroUtil.getCurrentUserID(),start,end);
}
/**
* 获取当前用户已经超时的任务
* @return
*/
public List<Task> findTimeOutTasks() {
String today = DateTime.now().toString("yyyy-MM-dd");
return taskMapper.findTimeOutTask(ShiroUtil.getCurrentUserID(),today);
}
/**
* 删除日程
* @param id
*/
public void delTask(Integer id) {
taskMapper.del(id);
}
/**
* 将日程设置为已完成
* @param id
*/
public Task doneTask(Integer id) {
Task task = taskMapper.findById(id);
task.setDone(true);
task.setColor("#cccccc");
taskMapper.update(task);
return task;
}
}