Quarz 动态定时器 实现过程

一直在考虑前段时间自己做动态定时器的内容,过程中也遇到问题,也是查询多个文档博客,现在梳理些详细的东西出来,避免一些弯路,废话不多说,上代码为主。

首先需要一个动态定时器的对象,存放相应的定时器任务内容。 其中内容可依照实际业务需求。本业务中有两类需求,一类需求是动态的更改,一类是动态更改数据,而且要动态恢复,以下就是实体类:

spring 整合需要的是quarz的相关的pom 依赖

applicationContext.xml 只需要注入schedulerFactoryBean

<!-- 配置任务调度中心 -->  
<bean id="schedulerFactoryBean"  class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
</bean> 


package com.osa.platform.domain.crontab;


import java.util.Date;


import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;


import org.hibernate.annotations.GenericGenerator;
import org.springframework.format.annotation.DateTimeFormat;


@Entity
@Table(name = "t_crontable_job")
public class CrontableJob {
@GenericGenerator(name = "idGenerator", strategy = "uuid")
@GeneratedValue(generator = "idGenerator")
@Id
@Column(length = 32)
private String id;      //任务id表
@Column(name="prize_name")
private String prizeName;
@Column(name = "reset_type")
private Integer resetType; //1.重置奖品数量     2.定时重置奖品策略 
@Column(name = "amount")
private Integer amount; //奖品数量
@Column(name = "prizeManagerId")
private String prizeManagerId; 
@Column(name = "startAmount_weight")
private Integer startAmountWeight;
@Column(name = "cron_type")
private Integer cronType;   // 每天   1   每周一  2  每个月一号  3 每周一到周五  4  每周六,周日 5
@Column(name = "end_time")
@DateTimeFormat(pattern="yyyy-MM-dd") 
private Date endTime; //任务有效结束时间
@Column(name = "start_time")
@DateTimeFormat(pattern="yyyy-MM-dd") 
private Date startTime;    //任务有效开始时间
@Column(name = "jobname")
private String JobName; //任务名称
@Column(name = "groups")
private String groups;
@Column(name = "job_status")
private Integer jobStatus; //任务的状态
@Column(name = "creater")
private String creater;
@Column(name = "create_time")
private Date createTime;
@Column(name = "strategyWeight")
private Integer strategyWeight;
@Column(name = "operater")
private String operater;
@Column(name = "operate_time")
private Date operateTime;
@Column(name = "cronExpression")
private String cronExpression;  //执行定时任务时间
@Column(name = "time")
private String time;    //任务执行的时间
@Column(name = "recoverTime")
private String recoverTime; //策略恢复时间
@Column(name = "recoverCronExpression")
private String recoverCronExpression;  //策略恢复表达式
@Column(name = "resetStatus")
private Integer resetStatus;   //默认是1 ,修改后为2
@Column(name = "descs")
private String desc;  //任务的描述
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPrizeName() {
return prizeName;
}
public void setPrizeName(String prizeName) {
this.prizeName = prizeName;
}
public Integer getResetType() {
return resetType;
}
public void setResetType(Integer resetType) {
this.resetType = resetType;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
public String getPrizeManagerId() {
return prizeManagerId;
}
public void setPrizeManagerId(String prizeManagerId) {
this.prizeManagerId = prizeManagerId;
}
public Integer getStartAmountWeight() {
return startAmountWeight;
}
public void setStartAmountWeight(Integer startAmountWeight) {
this.startAmountWeight = startAmountWeight;
}
public Integer getCronType() {
return cronType;
}
public void setCronType(Integer cronType) {
this.cronType = cronType;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public String getJobName() {
return JobName;
}
public void setJobName(String jobName) {
JobName = jobName;
}
public String getGroups() {
return groups;
}
public void setGroups(String groups) {
this.groups = groups;
}
public Integer getJobStatus() {
return jobStatus;
}
public void setJobStatus(Integer jobStatus) {
this.jobStatus = jobStatus;
}
public String getCreater() {
return creater;
}
public void setCreater(String creater) {
this.creater = creater;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Integer getStrategyWeight() {
return strategyWeight;
}
public void setStrategyWeight(Integer strategyWeight) {
this.strategyWeight = strategyWeight;
}
public String getOperater() {
return operater;
}
public void setOperater(String operater) {
this.operater = operater;
}
public Date getOperateTime() {
return operateTime;
}
public void setOperateTime(Date operateTime) {
this.operateTime = operateTime;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getRecoverTime() {
return recoverTime;
}
public void setRecoverTime(String recoverTime) {
this.recoverTime = recoverTime;
}
public String getRecoverCronExpression() {
return recoverCronExpression;
}
public void setRecoverCronExpression(String recoverCronExpression) {
this.recoverCronExpression = recoverCronExpression;
}
public Integer getResetStatus() {
return resetStatus;
}
public void setResetStatus(Integer resetStatus) {
this.resetStatus = resetStatus;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}


}

组装定时任务时间表达式:

package com.osa.platform.contants;


import org.apache.commons.lang3.StringUtils;


public interface JobCronExpress {

public static enum CronEnum {
everDay("* * ?",1),everyMonday("? * MON",2),everyFirst("1 * ?",3),everyWorkDay("? * MON-FRI",4),everyBreakDay("? * SAT,SUN",5);

    private final String cron;
private final Integer type;
private CronEnum(String cron, Integer type) {
        this.cron = cron;
        this.type = type;
    }


    public static String getCron(Integer type) {
        for (CronEnum c : CronEnum.values()) {
            if (c.getType() == type) {
                return c.getCron();
            }
        }
        return StringUtils.EMPTY;
    }


public String getCron() {
return cron;
}


public Integer getType() {
return type;
}
}
}

对定时器任务对象crontableJob进行重新调整,带上执行时间

package com.osa.utils;


import org.apache.commons.lang3.StringUtils;


import com.osa.auth.exception.JobException;
import com.osa.platform.contants.JobCronExpress;
import com.osa.platform.domain.crontab.CrontableJob;
/**
 * 获取带有执行时间表达是的定时job类
 * @author hq
 * @version 创建时间:2018年1月29日 下午4:21:27
 */
public class CrontableJobUtils {

/**
* 获取带有定时器时间表达式的内容
* @author hq
* @version 创建时间:2018年1月29日 下午3:26:10 
* @param crontableJob
* @return
*/
public static CrontableJob gainCrontableJob(CrontableJob crontableJob){
if(crontableJob!=null){
String time = crontableJob.getTime();
Integer cronType = crontableJob.getCronType();
String timestage="";
String timeRecover="";
String cron = JobCronExpress.CronEnum.getCron(cronType);
if(StringUtils.isNotBlank(time)&&StringUtils.isNotBlank(cron)){
String[] times = time.split(":");
if(times.length>1){
if(times.length==2){
timestage="0 ";
}
for (int i = times.length-1; i >=0; i--) {
if(times[i].startsWith("0")){
times[i].substring(1,times.length-1);
}
timestage+=times[i]+" ";
}
String ExcuteTime="";
ExcuteTime=timestage+cron;
crontableJob.setCronExpression(ExcuteTime);
}else{
throw new JobException("时间参数错误");
}

   if(crontableJob.getResetType()==2){
   String[] timex = crontableJob.getRecoverTime().split(":");
   String recoverTime="";
   if(timex.length>1){
   if(timex.length==2){
   timeRecover="0 ";
}
for (int i = timex.length-1; i >=0; i--) {
timeRecover+=timex[i]+" ";
}
recoverTime=timeRecover+cron;
crontableJob.setRecoverCronExpression(recoverTime);
}else{
throw new JobException("时间参数错误");
}
   
   }
  return crontableJob;
}
}
return null;
}


}

动态定时任务保存或者修改:

/**
* 保存或者修改定时任务
* @author hq
* @version 创建时间:2018年1月30日 下午2:50:58 
* @param list
* @return
*/
@Transactional
public CrontableJob saveOrUpdateContableJob(CrontableJob crontableJobx){
CrontableJob crontableJob = insertCrontableJob(crontableJobx);
Scheduler scheduler = (Scheduler)SpringUtils.getBean("schedulerFactoryBean");
saveOrUpdatePrizeJob(crontableJob, scheduler);
if(crontableJob.getResetType()==2){
CrontableJob crontableJob2 = new CrontableJob();
try {
ConvertUtils.register(new DateConverter(null), java.util.Date.class);
BeanUtils.copyProperties(crontableJob2, crontableJob);
crontableJob2.setJobName(crontableJob2.getJobName()+"recover");
}catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
saveOrUpdateRevoverJob(crontableJob2, scheduler);
}
return crontableJobx;

}


将任务保存到数据库部分:

/**
* 保存定时任务      保存或者修改动态定时器内容时意味着定时器重新开始了,之前若有执行也不再执行了
* @author hq
* @version 创建时间:2018年1月30日 下午6:50:21 
* @param crontableJobx
* @return
*/
private CrontableJob insertCrontableJob(CrontableJob crontableJobx) {
//获取时间表达式
CrontableJob crontableJob = CrontableJobUtils.gainCrontableJob(crontableJobx);
crontableJob.setStartTime(DateUtils.getDDateStart(crontableJob.getStartTime()));
crontableJob.setEndTime(DateUtils.getDDateEnd(crontableJob.getEndTime()));
StringBuffer jobName = new StringBuffer();
PrizeManager prizeManager = strategyDao.findprizeManagerByIds(crontableJob.getPrizeManagerId());
crontableJob.setPrizeName(prizeManager.getPrizeName());
if(crontableJob.getResetType()==2){
jobName.append("resetStrategy").append(crontableJob.getPrizeManagerId());
crontableJob.setGroups("resetStrategy");
crontableJob.setResetStatus(1);
crontableJob.setStartAmountWeight(prizeManager.getWeight());
}else{
crontableJob.setGroups("prize");
jobName.append("prize").append(crontableJob.getPrizeManagerId());
}
User user = SysUser.getUser();
crontableJob.setCreater(user.getUsername());
crontableJob.setCreateTime(new Date());
crontableJob.setJobName(jobName.toString());
crontableJob.setJobStatus(1);
excuteJobDao.saveOrUpdate(crontableJob);
return crontableJob;
}

两类定时器的更新或者保存:

public void saveOrUpdatePrizeJob(CrontableJob crontableJob, Scheduler scheduler) {
//获取相应的trigger
TriggerKey triggerKey = TriggerKey.triggerKey(crontableJob.getJobName(), crontableJob.getGroups());
try {
CronTrigger Trigger = (CronTrigger)scheduler.getTrigger(triggerKey);
CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(crontableJob.getCronExpression()).withMisfireHandlingInstructionDoNothing();
//cronSchedule(crontableJob.getCronExpression()).withMisfireHandlingInstructionDoNothing();
if(Trigger==null){

JobDetail jobDetail = JobBuilder.newJob(ExcuteJob.class).withIdentity(crontableJob.getJobName(), crontableJob.getGroups()).build();

                                //此步骤是关联任务以及后期执行操作的关键,可以灵活的进行任务的执行,类似执行的消息传递

jobDetail.getJobDataMap().put("crontableJob", crontableJob);
//按新的cronExpression表达式构建一个新的trigger  
Trigger = TriggerBuilder.newTrigger().withIdentity(crontableJob.getJobName(), crontableJob.getGroups()).withSchedule(cronSchedule).build();  
scheduler.scheduleJob(jobDetail, Trigger);
}else{
//Trigger已存在,那么更新相应的定时设置  
        //按新的cronExpression表达式重新构建trigger  
Trigger = Trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronSchedule).build();  
        //按新的trigger重新设置job执行  
        scheduler.rescheduleJob(triggerKey, Trigger);
}

} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
}

}

public void saveOrUpdateRevoverJob(CrontableJob crontableJob, Scheduler scheduler) {
//获取相应的trigger
TriggerKey triggerKey = TriggerKey.triggerKey(crontableJob.getJobName(), crontableJob.getGroups());
try {
CronTrigger Trigger = (CronTrigger)scheduler.getTrigger(triggerKey);
CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(crontableJob.getRecoverCronExpression());
if(Trigger==null){
JobDetail jobDetail = JobBuilder.newJob(ExcuteJob.class).withIdentity(crontableJob.getJobName(), crontableJob.getGroups()).build();
jobDetail.getJobDataMap().put("crontableJob", crontableJob);
//按新的cronExpression表达式构建一个新的trigger  
Trigger = TriggerBuilder.newTrigger().withIdentity(crontableJob.getJobName(), crontableJob.getGroups()).withSchedule(cronSchedule).build();  
scheduler.scheduleJob(jobDetail, Trigger);
}else{
//Trigger已存在,那么更新相应的定时设置  
        //按新的cronExpression表达式重新构建trigger  
Trigger = Trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronSchedule).build();  
        //按新的trigger重新设置job执行  
        scheduler.rescheduleJob(triggerKey, Trigger);
}

} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

最后就是任务执行的方法了

package com.osa.platform.service;


import java.lang.reflect.Method;
import java.util.Date;


import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.osa.platform.domain.crontab.CrontableJob;
import com.osa.utils.SpringUtils;
/**
 * 定时执行的方法
 * @author hq
 * @version 创建时间:2018年1月30日 下午2:23:17
 */
@DisallowConcurrentExecution 
public class ExcuteJob implements Job{
private static final Logger LOGGER=LoggerFactory.getLogger(ExcuteJob.class);
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
CrontableJob crontableJob=(CrontableJob)context.getMergedJobDataMap().get("crontableJob");
Object bean = SpringUtils.getBean("excuteJobService");
long date = new Date().getTime();
if(crontableJob!=null){
if(date>=crontableJob.getStartTime().getTime()&&date<=crontableJob.getEndTime().getTime()){
if(crontableJob.getResetType()==1){
try {
Method method = bean.getClass().getDeclaredMethod("resetPrizeAmount",CrontableJob.class);
method.invoke(bean, new Object[]{crontableJob});
} catch (Exception e) {
System.out.println(e.getMessage());
LOGGER.info("执行定时修改奖品数量异常");
}
}
else if(crontableJob.getResetType()==2){
try {
Method method = bean.getClass().getDeclaredMethod("resetStrategy",CrontableJob.class);
method.invoke(bean, new Object[]{crontableJob});
} catch (Exception e) {
System.out.println(e.getMessage());
LOGGER.info("执行定时修改策略权重异常");
}
}
}

}

}


}

具体执行的类容就不便给出了,亲测有效,发现在服务器关闭,或者tomcat关闭之后就会丢失任务,做法是初始化就去加载相应的任务列表信息。欢迎大神给出意见,建议,代码如有问题,欢迎指正(毕竟算个代码的搬运工)。

猜你喜欢

转载自blog.csdn.net/weixin_39735548/article/details/80519434