spring自带的@Scheduled 定时器只能在后台固定时间进行处理业务. 无法动态实现定时任务
前段时间项目要求需要从前台向后台传递执行时间动态执行业务代码,从网上找资料了解到Quartz 创建job来实现.
Quartz 设计有三个核心类,分别是 Scheduler(调度器)Job(任务)和 Trigger (触发器),它们是我们使用 Quartz 的关键。
2.1 Scheduler接口
Scheduler翻译成调度器,Quartz通过调度器来注册、暂停、删除Trigger和JobDetail。Scheduler还拥有一个SchedulerContext,顾名思义就是上下文,通过SchedulerContext我们可以获取到触发器和任务的一些信息。
2.2 Trigger接口
Trigger可以翻译成触发器,通过cron表达式或是SimpleScheduleBuilder等类,指定任务执行的周期。系统时间走到触发器指定的时间的时候,触发器就会触发任务的执行。
2.3 JobDetail接口
Job接口是真正需要执行的任务。JobDetail接口相当于将Job接口包装了一下,Trigger和Scheduler实际用到的都是JobDetail。
接下来我来回顾一下 实现步骤
- 首先将Quartz 的包集成到项目中
quartz-2.3.0-SNAPSHOT.jar quartz-jobs-2.3.0-SNAPSHOT.jar
- 创建 job 任务类 继承quartz包中的job类 重写 execute方法写定时任务业务逻辑.
public class TimingUpdatePrice implements Job { //货源合同列表 service层 private HtLogisticsOrderDetailService htLogisticsOrderDetailService = SpringContextHolder.getBean(HtLogisticsOrderDetailService.class); //货源单价修改记录表 service 层 private HtOrderDetailModificationHistoryService htOrderDetailModificationHistoryService = SpringContextHolder.getBean(HtOrderDetailModificationHistoryService.class); private HtTransportDetailService htTransportDetailService = SpringContextHolder.getBean(HtTransportDetailService.class); /** * 写定时任务业务逻辑 * @param jobExecutionContext * @throws JobExecutionException */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取当前对象 String historyId = jobExecutionContext.getTrigger().getJobKey().toString().replace(QuartzManage.TRIGGER_GROUP_NAME + ".", ""); HtOrderDetailModificationHistory htOrderDetailModificationHistory = htOrderDetailModificationHistoryService.get(historyId); try{ HtLogisticsOrderDetail htLogisticsOrderDetail = new HtLogisticsOrderDetail(); if(htOrderDetailModificationHistory !=null){ htLogisticsOrderDetail = htLogisticsOrderDetailService.get(htOrderDetailModificationHistory.getOrderDetailId()); if("1".equals(htOrderDetailModificationHistory.getPriceType())){//开票运费单价 htLogisticsOrderDetail.setFreight(htOrderDetailModificationHistory.getFreight()); htLogisticsOrderDetail.setPriceType("1"); htLogisticsOrderDetail.setActualPrice(null); }else {//实际运费单价 htLogisticsOrderDetail.setActualPrice(htOrderDetailModificationHistory.getActualPrice());//实际运费单价 htLogisticsOrderDetail.setPriceType("2"); htLogisticsOrderDetail.setFreight(null); } htLogisticsOrderDetail.setId(htOrderDetailModificationHistory.getOrderDetailId()); } htTransportDetailService.save(htLogisticsOrderDetail,htOrderDetailModificationHistory); // htLogisticsOrderDetailService.save(htLogisticsOrderDetail,htOrderDetailModificationHistory); // htOrderDetailModificationHistory.setIsDone("1"); // htOrderDetailModificationHistoryService.save(htOrderDetailModificationHistory); QuartzManage.removeJob(historyId); }catch (Exception e) { e.printStackTrace(); } }
- 写调度器类
public class QuartzManage { private static SchedulerFactory sf = new StdSchedulerFactory(); public static final String TRIGGER_GROUP_NAME = "trigger1"; /** * 添加一个任务 * * @param jobName--任务名称 * @param job--任务执行对象 * @param time--任务触发时机 * @throws Exception */ public static void addJob(Job job, String time, String jobName) throws Exception { boolean isValidate = CronExpression.isValidExpression(time); if (!isValidate) return; Scheduler sched = sf.getScheduler(); JobKey jobKey = new JobKey(jobName, TRIGGER_GROUP_NAME); JobDetail jobDetail = JobBuilder.newJob(job.getClass()).withIdentity(jobKey).build(); Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobName) // 每隔一秒执行 并一直重复 .withSchedule(CronScheduleBuilder.cronSchedule(time)).build(); sched.scheduleJob(jobDetail, trigger); // 启动 if (!sched.isShutdown()) { sched.start(); } } /** * 修改定时任务 * * @param jobName * @param time * @throws Exception */ public static void modifyJobTime(Job job, String time, String jobName) throws Exception { boolean isValidate = CronExpression.isValidExpression(time); if (!isValidate) return; removeJob(jobName); addJob(job, time, jobName); } /** * 移除任务 * * @param jobName * @throws Exception */ public static void removeJob(String jobName) throws Exception { Scheduler sched = sf.getScheduler(); JobKey jobKey = new JobKey(jobName, TRIGGER_GROUP_NAME); sched.pauseJob(jobKey);// 停止触发器 //sched.shutdown(false);// 移除触发器 sched.deleteJob(jobKey);// 删除任务 } }
-
在业务代码中调用 调度器
public Map<String,Object> save(HttpServletRequest request,HtOrderDetailModificationHistory htOrderDetailModificationHistory) {
Map<String,Object> result = Maps.newHashMap();
try {
String message = validateModel(htOrderDetailModificationHistory);
if (StringUtils.isNotBlank(message)){
result.put("flag", false);
result.put("message", message);
return result;
}
//设置通用属性
setCommonProperties(request,htOrderDetailModificationHistory);
htOrderDetailModificationHistory.setIsDone("0");//不能放到service层
htOrderDetailModificationHistoryService.save(htOrderDetailModificationHistory);
String cron = CronExpressionUtils.cronGen(htOrderDetailModificationHistory.getPeriodicModificationTime());
QuartzManage.addJob(new TimingUpdatePrice(), cron, htOrderDetailModificationHistory.getId());
result.put("flag", true);
result.put("message", "保存货源单价修改记录成功");
} catch (Exception e) {
result.put("flag", false);
result.put("message", e.toString());
}
return result;
}
5. 若程序重启了 内存中的 job任务就不存在了, 需要放在监听器中重新将这些任务加载进来.
这个监听器类 我加web.xml中配置的
<listener>
<listener-class>com.xiangyou.modules.sys.listener.WebContextListener</listener-class>
</listener>
public class WebContextListener extends org.springframework.web.context.ContextLoaderListener {
@Override
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (!SystemService.printKeyLoadMessage()){
return null;
}
WebApplicationContext context = super.initWebApplicationContext(servletContext);
//获取所有的有时效的绑定数据
HtOrderDetailModificationHistoryService htOrderDetailModificationHistoryService = context.getBean(HtOrderDetailModificationHistoryService.class);
try{
HtOrderDetailModificationHistory htOrderDetailModificationHistory = new HtOrderDetailModificationHistory();
htOrderDetailModificationHistory.setIsDone("0");
//循环列表,判断是否过期,如果过期,则直接执行,否则添加入定时任务
List<HtOrderDetailModificationHistory> list = htOrderDetailModificationHistoryService.findList(htOrderDetailModificationHistory);
Date modificationTime = null;
for (HtOrderDetailModificationHistory htOrderDetailModificationHistory1 : list) {
modificationTime = htOrderDetailModificationHistory1.getPeriodicModificationTime();
if(modificationTime.before(new Date())){ //已经过期
String cron = CronExpressionUtils.cronGen(new Date());
QuartzManage.addJob(new TimingUpdatePrice(), cron, htOrderDetailModificationHistory1.getId());
}else{
String cron = CronExpressionUtils.cronGen(modificationTime);
QuartzManage.addJob(new TimingUpdatePrice(), cron, htOrderDetailModificationHistory1.getId());
}
}
}catch (Exception e) {
e.printStackTrace();
}
return context;
}
}