1. 程式人生 > >動態配置定時任務(Mysql+重啟服務後重新載入任務)

動態配置定時任務(Mysql+重啟服務後重新載入任務)

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註解(具體意思自己百度)