Spring 整合 Quartz 實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)
Quartz 基本概念及原理
作為一個(gè)優(yōu)秀的開源調(diào)度框架耕漱,Quartz 具有以下特點(diǎn):
1潜慎、強(qiáng)大的調(diào)度功能,例如支持豐富多樣的調(diào)度方法子姜,可以滿足各種常規(guī)及特殊需求洗做;
2、 靈活的應(yīng)用方式址芯,例如支持任務(wù)和調(diào)度的多種組合方式灾茁,支持調(diào)度數(shù)據(jù)的多種存儲(chǔ)方式;
3谷炸、分布式和集群能力北专,Terracotta 收購后在原來功能基礎(chǔ)上作了進(jìn)一步提升。本文暫不討論該部分內(nèi)容旬陡。
作為 spring 默認(rèn)的調(diào)度框架拓颓,Quartz 很容易與 Spring 集成實(shí)現(xiàn)靈活可配置的調(diào)度功能。
Quartz專用詞匯:
1. scheduler :任務(wù)調(diào)度器
2. trigger :觸發(fā)器描孟,用于定義任務(wù)調(diào)度時(shí)間規(guī)則
3. job :任務(wù)驶睦,即被調(diào)度的任務(wù) misfire :錯(cuò)過的,指本來應(yīng)該被執(zhí)行但實(shí)際沒有被執(zhí)行的任務(wù)調(diào)度
Quartz 核心元素關(guān)系圖
job任務(wù)
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 觸發(fā)器
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);*/
//任務(wù)
JobDetail jobDetail = JobBuilder.newJob(MyQuartzJob.class).build();
//創(chuàng)建觸發(fā)器
/*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();
//創(chuàng)建調(diào)度器
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) // 任務(wù)執(zhí)行類
.withIdentity("job1_1", "jGroup1")// 任務(wù)名画拾,任務(wù)組
.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());// 停止觸發(fā)器
scheduler.unscheduleJob(trigger.getKey());// 移除觸發(fā)器
scheduler.deleteJob(trigger.getJobKey());
System.out.println("job cancel");
break;
}
Thread.sleep(3000L);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Spring 3 調(diào)度器示例 —— JDK 定時(shí)器和 Quartz 展示 【已翻譯100%】
與spring結(jié)合
創(chuàng)建任務(wù)
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已經(jīng)納入spring管理了這邊不用寫-->
<!--JobDetail-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="mySpringJob"/>
<property name="targetMethod" value="sayHello"/>
</bean>
<!--觸發(fā)器-->
<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>
動(dòng)態(tài)添加
動(dòng)態(tài)添加
job包中的TaskRemindJob類
cron pom依賴時(shí)分秒轉(zhuǎn)換成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("提醒內(nèi)容:" + 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);
/**
* 添加待辦任務(wù)
* @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("提醒時(shí)間為{}" , reminderTime);
task.setRemindertime(reminderTime);
task.setUserid(ShiroUtil.getCurrentUserID());
taskMapper.save(task);
//TODO Quartz動(dòng)態(tài)任務(wù)
//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);
}
}
/**
* 獲取當(dāng)前用戶的所有任務(wù)
* @return
*/
public List<Task> findTaskByUserId(String start,String end) {
return taskMapper.findByUserIdAndDateRanger(ShiroUtil.getCurrentUserID(),start,end);
}
/**
* 獲取當(dāng)前用戶已經(jīng)超時(shí)的任務(wù)
* @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);
}
/**
* 將日程設(shè)置為已完成
* @param id
*/
public Task doneTask(Integer id) {
Task task = taskMapper.findById(id);
task.setDone(true);
task.setColor("#cccccc");
taskMapper.update(task);
return task;
}
}