動態配置定時任務(Mysql+重啟服務後重新載入任務)
阿新 • • 發佈:2019-02-15
jar包版本
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.1.1</version>
</dependency>
spring版本:3.2.3
1.資料庫欄位
id(後面用於任務id), Event(裡面可包括任務執行時的相關引數資訊), Status(當前任務狀態), ExecutionTime(任務執行時間), 其餘欄位更據自己需要配置
2. 需要用到的配置類及工具類
1.ScheduleJob(任務物件)
package com.kkgame.sspop.schedule.util;
import com.kkgame.sspop.schedule.bean.CampaignScheduleVO;
import com.kkgame.sspop.schedule.bean.OfferScheduleVO;
/**
* 計劃任務資訊
*
* User: liyd
* Date: 14-1-3
* Time: 上午10:24
*/
public class ScheduleJob {
/** 任務id */
private String jobId;
/** 任務名稱 */
private String jobName;
/** 任務分組 */
private String jobGroup;
/** 任務狀態 0禁用 1啟用 2刪除*/
private String jobStatus;
/** 任務執行時間表達式 */
private String cronExpression;
/** 任務描述 */
private String desc;
/** 任務型別*/
private int type;
//
private CampaignScheduleVO campaignScheduleVO;
private OfferScheduleVO offerScheduleVO;
//get set
public String getJobId() {
return jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getJobStatus() {
return jobStatus;
}
public void setJobStatus(String jobStatus) {
this.jobStatus = jobStatus;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public CampaignScheduleVO getCampaignScheduleVO() {
return campaignScheduleVO;
}
public void setCampaignScheduleVO(CampaignScheduleVO campaignScheduleVO) {
this.campaignScheduleVO = campaignScheduleVO;
}
public OfferScheduleVO getOfferScheduleVO() {
return offerScheduleVO;
}
public void setOfferScheduleVO(OfferScheduleVO offerScheduleVO) {
this.offerScheduleVO = offerScheduleVO;
}
}
2.QuartzManager(定時任務管理類,任務新增,刪除暫停等方法)
package com.kkgame.sspop.schedule.util;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
/**
*
* @Description
* @author felix
*/
public class QuartzManager {
private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();
private static String JOB_GROUP_NAME = "MY_JOBGROUP_NAME";
private static String TRIGGER_GROUP_NAME = "MY_TRIGGERGROUP_NAME";
/**
* @Description: 新增一個定時任務,使用預設的任務組名,觸發器名,觸發器組名
* @param jobName 任務名
* @param cls 任務
* @param time 時間設定,參考quartz說明文件
* qgw 2016年1月21日 下午3:30:10 ^_^
*/
@SuppressWarnings("unchecked")
public static void addJob(String jobName, Class cls, String time,Object scheduleJob) {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
JobDetail job = JobBuilder.newJob(cls)
.withIdentity(jobName, JOB_GROUP_NAME)
.build();
// 新增具體任務方法
job.getJobDataMap().put("scheduleJob", scheduleJob);
// 表示式排程構建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time);
// 按新的cronExpression表示式構建一個新的trigger
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(jobName, TRIGGER_GROUP_NAME)
.withSchedule(scheduleBuilder).build();
//交給scheduler去排程
sched.scheduleJob(job, trigger);
// 啟動
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 新增一個定時任務
* @param jobName 任務名
* @param jobGroupName 任務組名
* @param triggerName 觸發器名
* @param triggerGroupName 觸發器組名
* @param jobClass 任務
* @param time 時間設定,參考quartz說明文件
* qgw 2016年1月21日 下午3:27:00 ^_^
*/
@SuppressWarnings("unchecked")
public static void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class jobClass,
String time) {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
JobDetail job = JobBuilder.newJob(jobClass)
.withIdentity(jobName, jobGroupName)
.build();
// 表示式排程構建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time);
// 按新的cronExpression表示式構建一個新的trigger
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.withSchedule(scheduleBuilder).build();
sched.scheduleJob(job, trigger);
// 啟動
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一個任務的觸發時間(使用預設的任務組名,觸發器名,觸發器組名)
* @param jobName
* @param time
* qgw 2016年1月21日 下午3:28:34 ^_^
*/
@SuppressWarnings("unchecked")
public static void modifyJobTime(String jobName, String time) {
TriggerKey triggerKey = TriggerKey.triggerKey(
jobName, TRIGGER_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
CronTrigger trigger =(CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
CronScheduleBuilder scheduleBuilder =CronScheduleBuilder.cronSchedule(time);
//按新的cronExpression表示式重新構建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//按新的trigger重新設定job執行
sched.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一個任務的觸發時間
* @param triggerName
* @param triggerGroupName
* @param time
* @author qgw
* @date 2016年1月27日 下午4:45:15 ^_^
*/
public static void modifyJobTime(String triggerName,
String triggerGroupName, String time) {
TriggerKey triggerKey = TriggerKey.triggerKey(
triggerName, triggerGroupName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
// trigger已存在,則更新相應的定時設定
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
.cronSchedule(time);
// 按新的cronExpression表示式重新構建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
// 按新的trigger重新設定job執行
sched.resumeTrigger(triggerKey);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description 移除一個任務(使用預設的任務組名,觸發器名,觸發器組名)
* @param jobName
* @author qgw
* @date 2016年1月29日 下午2:21:16 ^_^
*/
public static void removeJob(String jobName) {
TriggerKey triggerKey = TriggerKey.triggerKey(
jobName, TRIGGER_GROUP_NAME);
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
Trigger trigger = (Trigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
sched.pauseTrigger(triggerKey);;// 停止觸發器
sched.unscheduleJob(triggerKey);// 移除觸發器
sched.deleteJob(jobKey);// 刪除任務
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一個任務
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
* @author qgw
* @date 2016年1月29日 下午2:21:16 ^_^
*/
public static void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
TriggerKey triggerKey = TriggerKey.triggerKey(
jobName, triggerGroupName);
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.pauseTrigger(triggerKey);// 停止觸發器
sched.unscheduleJob(triggerKey);// 移除觸發器
sched.deleteJob(jobKey);// 刪除任務
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:暫停一個任務
* @param jobName
* @param jobGroupName
* qgw 2016年1月22日 下午4:24:55 ^_^
*/
public static void pauseJob(String jobName, String jobGroupName) {
JobKey jobKey =JobKey.jobKey(jobName, jobName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.pauseJob(jobKey);
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @Description:暫停一個任務(使用預設組名)
* @param jobName
* @param jobGroupName
* qgw 2016年1月22日 下午4:24:55 ^_^
*/
public static void pauseJob(String jobName) {
JobKey jobKey =JobKey.jobKey(jobName, JOB_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description:啟動所有定時任務
* @author qgw
* @date 2016年1月29日 下午2:21:16 ^_^
*/
public static void startJobs() {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description 關閉所有定時任務
* @author qgw
* @date 2016年1月25日 下午2:26:54 ^_^
*/
public static void shutdownJobs() {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
3.QuartzJobFactory (定時任務執行(反射出來的類),具體執行的操作寫在裡面)
package com.kkgame.sspop.schedule.util;
import javax.annotation.PostConstruct;
import org.apache.log4j.Logger;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import com.kkgame.sspop.schedule.bean.CampaignScheduleVO;
import com.kkgame.sspop.schedule.bean.OfferScheduleVO;
import com.kkgame.sspop.schedule.service.CampaignScheduleService;
import com.kkgame.sspop.schedule.service.OfferScheduleService;
import com.kkgame.sspop.util.CTX;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
/**
* 定時任務執行(反射出來的類)
* @Description
* @author felix
* 2016 下午2:39:37 ^_^
*/
@DisallowConcurrentExecution
public class QuartzJobFactory implements Job{
private CampaignScheduleService campaignScheduleService = CTX.getBeanByClass(CampaignScheduleService.class);
private OfferScheduleService offerScheduleService = CTX.getBeanByClass(OfferScheduleService.class);
private static final Logger log = Logger.getLogger("");
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.info("任務執行開始-------- start --------");
try {
//ScheduleJob任務執行時具體引數,可自定義
ScheduleJob scheduleJob =(ScheduleJob) context.getMergedJobDataMap().get("scheduleJob");//(從QuartzManager類中的addJob方法中傳入的引數,可自定義)
CampaignScheduleVO campaignScheduleVO = scheduleJob.getCampaignScheduleVO();
OfferScheduleVO offerScheduleVO = scheduleJob.getOfferScheduleVO();
String event = "";
if(campaignScheduleVO != null){
event = campaignScheduleVO.getEvent();
}else if(offerScheduleVO != null){
event = offerScheduleVO.getEvent();
}
JSONArray ja = JSONArray.fromObject(event);
for(int i=0;i<ja.size();i++){
JSONObject jb = ja.getJSONObject(i);
int type = jb.getInt("type");
String value = jb.getString("value");
/** type 1.campaign totalBudget 2. campaign Daily Budget 3.campaign Daily Conversions
4. adverPayout 5.publisherPayout 6. autoApproval 7. Offer Total Budget
8. offer daily budget 9.per publisher 10.daily conversions
*/
if(type==1){
campaignScheduleVO.setValue(value);
campaignScheduleService.updateCampaignTotalBudget(campaignScheduleVO);
}else if(type==2){
campaignScheduleVO.setValue(value);
campaignScheduleService.updateCampaignDailyBudget(campaignScheduleVO);
}else if(type==3){
campaignScheduleVO.setValue(value);
campaignScheduleService.updateCampaignDailyConversions(campaignScheduleVO);
}else if(type==4){
offerScheduleVO.setValue(value);
offerScheduleService.updateAdverPayout(offerScheduleVO);
}else if(type==5){
offerScheduleVO.setValue(value);
offerScheduleService.updatePublisherPayout(offerScheduleVO);
}else if(type==6){
offerScheduleVO.setValue(value);
offerScheduleService.updateAutoApprovalRate(offerScheduleVO);
}else if(type==7){
offerScheduleVO.setValue(value);
offerScheduleService.updateOfferTotalBudget(offerScheduleVO);
}else if(type==8){
offerScheduleVO.setValue(value);
offerScheduleService.updateOfferDailyBudget(offerScheduleVO);
}else if(type==9){
offerScheduleVO.setValue(value);
offerScheduleService.updatePerPublisher(offerScheduleVO);
}else if(type==10){
offerScheduleVO.setValue(value);
offerScheduleService.updateOfferDailyConversions(offerScheduleVO);
}else if(type==12){//開啟Offer
offerScheduleVO.setStatus(1);;
offerScheduleService.updateOfferStatus(offerScheduleVO);
}else if(type==13){//關閉Offer
offerScheduleVO.setStatus(0);;
offerScheduleService.updateOfferStatus(offerScheduleVO);
}else if(type==14){//開啟campaign
campaignScheduleVO.setStatus(1);
campaignScheduleService.updateCampaignStatus(campaignScheduleVO);
}else if(type==15){//關閉campaign
campaignScheduleVO.setStatus(0);
campaignScheduleService.updateCampaignStatus(campaignScheduleVO);
}
}
//執行後更新當前任務狀態
if(campaignScheduleVO==null){
campaignScheduleVO = new CampaignScheduleVO();
campaignScheduleVO.setId(offerScheduleVO.getId());
}
campaignScheduleVO.setStatus(2);
campaignScheduleService.updateCampaignScheduleVOStatus(campaignScheduleVO);
}catch (Exception e) {
log.info("捕獲異常==="+e);
}
log.info("任務執行結束-------- end --------");
}
}
4.LoadTask(新增定時任務到程序中)
package com.kkgame.sspop.schedule.util;
import java.util.Date;
import javax.annotation.PostConstruct;
import org.apache.log4j.Logger;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
/**
* 載入定時任務
* @Description
* @author qgw
* 2016 下午2:24:58 ^_^
*/
@SuppressWarnings("unchecked")
public class LoadTask {
private static final Logger log = Logger.getLogger("");
/**
* @param 執行時間
* @return
* @author qgw
* @date 2016年1月26日 下午3:39:13 ^_^
*/
public static void timerTask(ScheduleJob job) throws Exception { //doTime 格式為 "2018-03-19 13:50:00"
if(job.getCampaignScheduleVO() != null){//campaign 定時任務
if(!"".equals(job.getCampaignScheduleVO().getExecutionTime())){
addJob(job, job.getCampaignScheduleVO().getId(), job.getCampaignScheduleVO().getExecutionTime());
}
}else if(job.getOfferScheduleVO() != null){ // Offer定時任務
if(!"".equals(job.getOfferScheduleVO().getExecutionTime())){
addJob(job, job.getOfferScheduleVO().getId(), job.getOfferScheduleVO().getExecutionTime());
}
}
}
private static void addJob(ScheduleJob job,int id,String time){
String cron = CronFormatUtil.getCron(time);//獲得quartz時間表達式,此方法自己寫
String jobName = id+"_job";
job.setJobId(id+"");
job.setJobName(jobName);
job.setCronExpression(cron);
job.setJobGroup("MY_JOBGROUP_NAME");
//刪除已有的定時任務
QuartzManager.removeJob(jobName);
//新增定時任務
QuartzManager.addJob(jobName, QuartzJobFactory.class, cron,job);
}
public static void updateStatus(ScheduleJob job){
String jobName = "";
if(job.getCampaignScheduleVO() != null){
jobName = job.getCampaignScheduleVO().getId()+"_job";
}else if(job.getOfferScheduleVO().getId()>0){
jobName = job.getOfferScheduleVO().getId()+"_job";
}
try {
//刪除已有的定時任務
QuartzManager.removeJob(jobName);
} catch (Exception e) {
log.info("載入定時器錯誤:"+e);
}
}
//啟動專案時載入所有未執行的任務
@PostConstruct
public void initSchedule(){
try {
//初始化offer定時任務 start
List<OfferScheduleVO> initOfferScheduleList = offerScheduleService.getInitOfferScheduleList();
for(int i=0;i<initOfferScheduleList.size();i++){
OfferScheduleVO offerScheduleTemp = initOfferScheduleList.get(i);
//新增到任務列
ScheduleJob job = new ScheduleJob();
job.setOfferScheduleVO(offerScheduleTemp);
LoadTask.timerTask(job);
}
//初始化offer定時任務 end
//初始化campaign定時任務 start
List<CampaignScheduleVO> initCampaignScheduleList = campaignScheduleService.getInitCampaignScheduleList();
for(int i=0;i<initCampaignScheduleList.size();i++){
CampaignScheduleVO campaignScheduleTemp = initCampaignScheduleList.get(i);
//新增到任務列
ScheduleJob job = new ScheduleJob();
job.setCampaignScheduleVO(campaignScheduleTemp);
LoadTask.timerTask(job);
}
//初始化campaign定時任務 end
} catch (Exception e) {
e.printStackTrace();
}
}
//啟動專案時更新所有未執行並且已過時的任務的狀態 3.failed
@PostConstruct
public void initOutOfDateSchedule(){
try {
campaignScheduleService.updateOutOfDateScheduleStatus();
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.CronFormatUtil(”2011-07-09 18:00:00” 字串轉 cron格式時間)
package com.kkgame.sspop.schedule.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @author felix
* @Description "2011-07-09 18:00:00" 字串轉 cron格式時間
*/
public class CronFormatUtil {
/***
*
* @param date
* @param dateFormat : e.g:yyyy-MM-dd HH:mm:ss
* @return
*/
public static String formatDateByPattern(Date date,String dateFormat){
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
String formatTimeStr = null;
if (date != null) {
formatTimeStr = sdf.format(date);
}
return formatTimeStr;
}
/***
* convert Date to cron ,eg. "0 06 10 15 1 ? 2014"
* @param date : 時間點
* @return
*/
public static String getCron(String dateString){ //"2011-07-09 18:00:00"
SimpleDateFormat formatter = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss");
String dateFormat="ss mm HH dd MM ? yyyy";
Date date = null;
try {
date = formatter.parse(dateString);
} catch (ParseException e) {
e.printStackTrace();
}
return formatDateByPattern(date, dateFormat);
}
public static void main(String[] args) {
System.out.println(getCron("2018-03-19 18:01:02"));
}
}
3任務動態執行流程
1.前臺新增任務將資料儲存到後臺
a.前臺傳送相應的動態定時任務配置資訊,
b.後臺接收後先處理資訊並儲存到資料庫,並返回當前任務的Id.
OfferScheduleVO offerScheduleTemp;
offerScheduleTemp = offerScheduleDao.createOfferScheduleVO(offerScheduleVO);
c.將資料新增到程序任務中去
//新增到任務列
ScheduleJob job = new ScheduleJob();
job.setOfferScheduleVO(offerScheduleTemp);
LoadTask.timerTask(job);
此時定時任務已新增可以檢視執行結果
2.程式重啟時將資料庫中未執行且未過時的任務加入任務程序中
檢視 LoadTask中的initSchedule()方法注意要加上@PostConstruct註解(具體意思自己百度)