需要了解一下quartz有Job,Scheduler,Trigger等概念,在此就不详细说明
首先说一下功能需求场景
该提醒可以在页面上进行配置多个,比如可以配置一个提醒:在每天的12点,发送邮件给某个人,可以继续配置另外一个提醒:在每个月的10号,给某个人转账,等等,多个动态的提醒,
说一下实现的方式
上面的需求即通过页面的配置,创建出来对应的定时任务,这些任务是动态创建出来的,不能够在代码中固定,该本章采用了quartz的Scheduler任务调度来实现动态任务的创建
实现功能路上踩过的坑
最开始的时候,对于这个动态创建定时任务我也觉得一脸懵逼,于是就在网上查找资料
最开始采用https://blog.csdn.net/upxiaofeng/article/details/79415108 这篇文章的思路进行编码,最开始测试是可以的,项目启动,成功创建出来对应的定时任务,但是在定时任务到达执行时间的时候,在执行继承Job接口的类中,发现通过Autowired注入进来的对象为null,通过查资料一时也没有解决,项目使用的springboot,网上的都是通过xml进行配置,于是就放弃了这篇文章的实现,之后又找到另一篇文章https://blog.csdn.net/lyg_come_on/article/details/78223344,一路照着敲完,发现在
StdScheduler stdScheduler = (StdScheduler) annotationContext.getBean(“mySchedulerFactoryBean”);//获得上面创建的bean
的时候报错了,原来是项目启动的时候,先进行创建定时任务,但是此刻并没有初始化MyJobFactory类中的bean,导致在创建scheduler时候并没有在spring上下文中找到这个bean,于是就打算写一个定时器,然后每天执行一次,执行的时候,调用动态创建定时任务的方法,刚好这样做,可以实现,在页面上修改任务提醒的配置,后台不用重新启动就可以动态更新任务,现在要实现就是对动态创建出来的任务进行修改定时时间,新增定时任务的操作了.
实现
1. InitRemindRuleScheduler
2. JobFactory
3. RemindTask
4. RemindRuleScheduler
5. TimingRemindTask
说明一下,因为目前我的多个定期任务都是同一个任务逻辑操作,故只需要一个定时任务的业务逻辑实现,如果针对不同的任务,有不同的实现的话,在创建定时任务的时候,要针对生成这个任务的时候使用对应的类:TimingRemindTask(该类需实现Job接口)
JobDetail jobDetail = JobBuilder.newJob(TimingRemindTask.class)
.withIdentity(remindRuleObjF04SQL01OM01.getId(), REMINDRULE )
.usingJobData("remindRuleId",remindRuleObjF04SQL01OM01.getId())
.build();
最后,贴上代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import com.paasit.pai.core.quartz.RemindRuleScheduler;
/**
* @author 和彦鹏
* 2018年9月15日
*/
@Configuration
public class InitRemindRuleScheduler implements ApplicationListener<ContextRefreshedEvent> {
/**
* 日志
*/
private final Logger log = LoggerFactory.getLogger(InitRemindRuleScheduler.class);
@Autowired
private RemindRuleScheduler remindRuleScheduler;
@Autowired
private JobFactory jobFactory;
@Bean(name ="mySchedulerFactoryBean")
public SchedulerFactoryBean mySchedulerFactory() {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setOverwriteExistingJobs(true);
bean.setStartupDelay(1);
bean.setJobFactory(jobFactory);
return bean;
}
/**
* 项目初始化的时候启动quartz
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//log.debug("执行onApplicationEvent..");
//try {
// remindRuleScheduler.initStartJob();
// log.debug("任务已经启动...");
//} catch (SchedulerException e) {
// log.error("初始化启动错误:{}", e);
//}
}
}
import org.quartz.spi.TriggerFiredBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
/**
* @author 和彦鹏
* 2018年9月16日
*/
@Component
public class JobFactory extends AdaptableJobFactory {
private static final Logger log = LoggerFactory.getLogger(JobFactory.class);
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @version: 0_1
* @author: 和彦鹏
* @date: 2018年6月6日11:37:44
*/
@Component
@Configurable
@EnableScheduling
public class RemindTask {
/**
* 日志
*/
private final Logger log = LoggerFactory.getLogger(RemindTask.class);
/**
* 初始化动态创建定期任务
*/
@Autowired
private RemindRuleScheduler remindRuleScheduler;
/**
* 执行间隔提醒业务逻辑
*/
@Autowired
private IntervalRemindTask intervalRemindTask;
// 每天执行定时任务:测试使用,每分钟执行
@Scheduled(cron = "5 * * * * ?")
public void testGetDemoData() {
log.debug("RemindTask starting...");
// A:创建或者更新定期的所有动态任务
try {
remindRuleScheduler.initStartJob();
} catch (SchedulerException e) {
log.error("RemindTask 初始化定期提醒任务失败.. {}", e);
}
log.debug("RemindTask end...");
}
}
import java.text.MessageFormat;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import com.paasit.pai.core.dao.QueryDAO;
import com.paasit.pai.core.sql.dto.remindRuleObj.RemindRuleObjF04SQL01IM01;
import com.paasit.pai.core.sql.dto.remindRuleObj.RemindRuleObjF04SQL01OM01;
import com.paasit.pai.core.utils.SpringUtil;
/**
* 描述: 提醒规则任务:
* @author 和彦鹏
* @date 2018年9月15日15:33:02
* @version v0.0.1
*/
@Component
public class RemindRuleScheduler {
/**
* 日志
*/
private final Logger log = LoggerFactory.getLogger(RemindRuleScheduler.class);
private final String REMINDRULE = "REMINDRULE";
@Autowired
private QueryDAO queryDAO;
/**
* 开始执行所有任务
*
* @throws SchedulerException
*/
public void initStartJob() throws SchedulerException {
// 从数据库中查询到所有的提醒
ApplicationContext annotationContext = SpringUtil.getApplicationContext();
StdScheduler stdScheduler = (StdScheduler) annotationContext.getBean("mySchedulerFactoryBean");//获得上面创建的bean
Scheduler myScheduler = stdScheduler;
RemindRuleObjF04SQL01IM01 remindRuleObjF04SQL01IM01 = new RemindRuleObjF04SQL01IM01();
remindRuleObjF04SQL01IM01.setRemindType(0);// 0表示定期,该方法仅执行定期
List<RemindRuleObjF04SQL01OM01> remindRuleObjF04SQL01OM01List = queryDAO.executeForObjectList("RemindRuleObjF04SQL01", remindRuleObjF04SQL01IM01);
log.debug("RemindTask 数据库查询出来的定期任务数量:{}", remindRuleObjF04SQL01OM01List.size());
if (remindRuleObjF04SQL01OM01List != null && remindRuleObjF04SQL01OM01List.size() > 0) {
for (int i = 0; i < remindRuleObjF04SQL01OM01List.size(); i++) {
startJob(myScheduler,remindRuleObjF04SQL01OM01List.get(i));
}
myScheduler.start();
}
}
private void startJob(Scheduler myScheduler, RemindRuleObjF04SQL01OM01 remindRuleObjF04SQL01OM01) throws SchedulerException {
// 创建触发器表达式{0}:表示小时,{1}:表示日,
String cron = MessageFormat.format("0 0 {0} {1} * ?",
remindRuleObjF04SQL01OM01.getOnHour() == null ? 0 : remindRuleObjF04SQL01OM01.getOnHour(),
remindRuleObjF04SQL01OM01.getOnDay() == null || remindRuleObjF04SQL01OM01.getOnDay() == 0 ? "*" : remindRuleObjF04SQL01OM01.getOnDay());
log.info(MessageFormat.format("RemindTask 提醒任务Id=[{0}]的cron的表达式:[{1}]", remindRuleObjF04SQL01OM01.getId(), cron));
TriggerKey triggerKey = new TriggerKey(remindRuleObjF04SQL01OM01.getId(), REMINDRULE);
CronTrigger cronTrigger = (CronTrigger) myScheduler.getTrigger(triggerKey);
// 不存在这个任务,新增任务
if (cronTrigger == null) {
// 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例
JobDetail jobDetail = JobBuilder.newJob(TimingRemindTask.class)
.withIdentity(remindRuleObjF04SQL01OM01.getId(), REMINDRULE)
.usingJobData("remindRuleId",remindRuleObjF04SQL01OM01.getId())
.build();
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
// CronTrigger表达式触发器 继承于Trigger
cronTrigger = TriggerBuilder.newTrigger().withIdentity(remindRuleObjF04SQL01OM01.getId(), REMINDRULE)
.withSchedule(cronScheduleBuilder).build();
myScheduler.scheduleJob(jobDetail, cronTrigger);
log.info("RemindTask 创建定时任务成功");
} else {// 存在这个任务,判断这个任务的触发时间是否被修改过,如果修改过则更新任务
String oldCron = cronTrigger.getCronExpression();
// 新配置的cron和之前任务中使用的不一致,则更新
if (!StringUtils.equalsIgnoreCase(cron, oldCron)) {
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(remindRuleObjF04SQL01OM01.getId(), REMINDRULE)
.withSchedule(cronScheduleBuilder).build();
myScheduler.rescheduleJob(triggerKey, trigger);
log.info("RemindTask 更新任务执行时间成功");
} else {
log.info("RemindTask 任务不进行操作");
}
} // TODO 暂没考虑页面上删除定期任务提醒
}
// /**
// * 获取Job信息
// */
// public String getJobInfo(String name, String group) throws SchedulerException {
// TriggerKey triggerKey = new TriggerKey(name, group);
// CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// return String.format("time:%s,state:%s", cronTrigger.getCronExpression(),
// scheduler.getTriggerState(triggerKey).name());
// }
//
// /**
// * 修改某个任务的执行时间
// */
// public boolean modifyJob(String name, String group, String time) throws SchedulerException {
// Date date = null;
// TriggerKey triggerKey = new TriggerKey(name, group);
// CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// String oldTime = cronTrigger.getCronExpression();
// if (!oldTime.equalsIgnoreCase(time)) {
// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(time);
// CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
// .withSchedule(cronScheduleBuilder).build();
// date = scheduler.rescheduleJob(triggerKey, trigger);
// }
// return date != null;
// }
//
// /**
// * 暂停所有任务
// */
// public void pauseAllJob() throws SchedulerException {
// scheduler.pauseAll();
// }
//
// /**
// * 暂停某个任务
// */
// public void pauseJob(String name, String group) throws SchedulerException {
// JobKey jobKey = new JobKey(name, group);
// JobDetail jobDetail = scheduler.getJobDetail(jobKey);
// if (jobDetail == null)
// return;
// scheduler.pauseJob(jobKey);
// }
//
// /**
// * 恢复所有任务
// */
// public void resumeAllJob() throws SchedulerException {
// scheduler.resumeAll();
// }
//
// /**
// * 恢复某个任务
// */
// public void resumeJob(String name, String group) throws SchedulerException {
// JobKey jobKey = new JobKey(name, group);
// JobDetail jobDetail = scheduler.getJobDetail(jobKey);
// if (jobDetail == null)
// return;
// scheduler.resumeJob(jobKey);
// }
//
// /**
// * 删除某个任务
// */
// public void deleteJob(String name, String group) throws SchedulerException {
// JobKey jobKey = new JobKey(name, group);
// JobDetail jobDetail = scheduler.getJobDetail(jobKey);
// if (jobDetail == null)
// return;
// scheduler.deleteJob(jobKey);
// }
}
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.paasit.pai.core.dao.QueryDAO;
import com.paasit.pai.core.sql.dto.remindRuleObj.RemindRuleObjF04SQL01IM01;
import com.paasit.pai.core.sql.dto.remindRuleObj.RemindRuleObjF04SQL01OM01;
/**
* 定时提醒的任务逻辑:该方法为动态创建出来的定时任务执行的逻辑,精确到remindRuleId,仅执行该条提醒的配置
* @author 和彦鹏
* @date 2018年9月16日15:33:09
* @version v0.1
*/
@Component
public class TimingRemindTask implements Job {
/**
* 日志
*/
private final Logger log = LoggerFactory.getLogger(TimingRemindTask.class);
@Autowired
private QueryDAO queryDAO;
public void execute(JobExecutionContext arg0) throws JobExecutionException {
try {
String remindRuleId = arg0.getJobDetail().getJobDataMap().getString("remindRuleId");
log.debug("RemindTask 1.1执行定期提醒任务信息Id:{}", remindRuleId);
RemindRuleObjF04SQL01IM01 remindRuleObjF04SQL01IM01 = new RemindRuleObjF04SQL01IM01();
remindRuleObjF04SQL01IM01.setId(remindRuleId);
RemindRuleObjF04SQL01OM01 remindRuleObjF04SQL01OM01 = queryDAO.executeForObject("RemindRuleObjF04SQL01", remindRuleObjF04SQL01IM01, RemindRuleObjF04SQL01OM01.class);
// 进行业务逻辑处理
} catch (Exception e) {
log.error("RemindTask 1.9执行任务,获取任务信息Id出错,任务信息:{}", arg0);
}
}
}