总结 Quartz hibernate修改quartz任务执行周期(二)
检测cron表达式变化任务
package com.jc.internal.quartz.task; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.quartz.CronTrigger; import org.quartz.Scheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import com.jc.common.utils.StringUtil; import com.jc.system.entity.SystemConfig; import com.jc.system.service.SystemConfigService; import com.jc.zhgc.service.ProductPlanService; import com.jc.zhgc.util.ChongyaUtil; /** * 监测CRON表达式变化任务,每隔一分钟执行一次 * @author wang-xiaoming * */ public class MonitorCronTask extends AbstractTask { /** * 日志打印对象 */ private Logger log = LoggerFactory.getLogger(MonitorCronTask.class); @Autowired private SchedulerFactoryBean factory; @Autowired private SystemConfigService systemConfigService; @Autowired ProductPlanService productPlanService; /** * 系统默认的定时任务分组 */ private static final String DEFAULT_SCHEDULE_GROUP = "DEFAULT"; /** * 触发器名字 */ private static final String TRIGGERNAME = "trigger"; /** * Cron表达式标识 */ private static final String CRON = "cron"; /** * Cron表达式默认值,每隔1分钟扫描数据 */ private static final String DEFAULT = "0 0/1 * * * ?"; public void doMonitorCron() throws Exception { log.info("**********执行监测CRON表达式变化任务开始**********"); // 获取当前 schedule 对象 Scheduler scheduler = factory.getScheduler(); if (null == scheduler) { log.info("执行监测CRON表达式变化任务,获取不到当前 schedule对象,此次不再尝试更新"); return; } // 读取系统配置参数,修改定时器任务执行频率 SystemConfig cron = systemConfigService.findByMark(CRON); if(cron == null){ cron = new SystemConfig(); cron.setMark(CRON); cron.setName("扫描时间间隔"); cron.setValue(DEFAULT); cron.setRemark("值为空,则默认1分钟一次"); systemConfigService.add(cron); log.info("执行监测CRON表达式变化任务,首次执行,初始化Cron(Cron表达式)系统参数完成"); } // 初始化系统参数 this.initConfig(); // 读取或修改指定任务执行频率异常,添加系统异常消息提醒 Map<String, SystemConfig> triggerMap = new HashMap<String, SystemConfig>(1); triggerMap.put(TRIGGERNAME, cron); this.updateScheduleTimeSet(scheduler, triggerMap); log.info("**********执行监测CRON表达式变化任务结束**********"); } private void initConfig(){ } /** * 刷新定时任务更新频率 * * @param scheduler * 日程对象 * @param triggers * 所有需要刷新的定时任务名称 * @throws Exception */ private void updateScheduleTimeSet(Scheduler scheduler, Map<String, SystemConfig> triggerMap) throws Exception { if (triggerMap.isEmpty()) { log.info("执行监测CRON表达式变化任务,无可控定时器触发器!"); return; } log.info("执行监测CRON表达式变化任务,可控定时器触发器{}个:分别是{}", triggerMap.size(), triggerMap.keySet()); for (Entry<String, SystemConfig> entry : triggerMap.entrySet()) { this.upgradeScheduleTimeSet(entry.getKey(), entry.getValue(), scheduler); } log.info("执行监测CRON表达式变化任务,刷新定时任务频率完成!"); } /** * 根据系统设置信息,更新定时任务的刷新频率(如果频率不变,则不刷新) * * @param triggerName * 定时任务的触发器名字(配置时指定) * @param systemConfigMark * (系统配置表的mark值) * @param scheduler * 当前日程对象 * @throws Exception */ private void upgradeScheduleTimeSet(String triggerName, SystemConfig systemConfig, Scheduler scheduler) { log.info("执行监测CRON表达式变化任务,刷新定时任务频率,触发器:{}", triggerName); if (StringUtil.isNullOrEmpty(systemConfig.getValue())) { log.info("执行监测CRON表达式变化任务,刷新定时任务频率,新的刷新频率为空!跳过!", triggerName); return; } try { // 1、获取当前定时器时间配置 String newCornSet = constructCronString(systemConfig.getValue()); if (StringUtil.isNullOrEmpty(newCornSet)) { log.info("执行监测CRON表达式变化任务,刷新定时任务频率,新的刷新频率表达式错误!cron格式校验不通过,跳过!", triggerName); return; } // 2、获取旧的定时器触发器,以获取旧的定时器频率。 log.info("执行监测CRON表达式变化任务,刷新定时任务频率,新的刷新频率为{}", newCornSet); CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger( triggerName, DEFAULT_SCHEDULE_GROUP); if (null == cronTrigger) { log.info("执行监测CRON表达式变化任务,刷新定时任务频率,未找到触发器!跳过!", triggerName); return; } // 3、定时器触发器存在时,才进行处理 log.info("执行监测CRON表达式变化任务,刷新定时任务频率,旧的刷新频率为{}", cronTrigger.getCronExpression(), newCornSet); if(cronTrigger.getCronExpression().equals(newCornSet)){ log.info("执行监测CRON表达式变化任务,刷新定时任务频率,刷新频率无变化!跳过!", triggerName); return; } log.info("执行监测CRON表达式变化任务,刷新定时任务频率,触发器【" + triggerName + "】的刷新频率发生变化,频率从" + cronTrigger.getCronExpression() + "重设为" + newCornSet); cronTrigger.setCronExpression(newCornSet); cronTrigger .setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING); scheduler.rescheduleJob(triggerName, DEFAULT_SCHEDULE_GROUP, cronTrigger); log.info("执行监测CRON表达式变化任务,刷新定时任务频率,触发器【{}】的刷新频率已重设!等待下次执行时生效!", triggerName); } catch (Exception e) { log.info("执行监测CRON表达式变化任务,刷新定时任务频率,触发器【{}】的刷新频率异常!e={}", triggerName, e); } } /** * 根据指定格式配置获取 CORN 表达式 * * @param date * @return */ private String constructCronString(String cron) { if (StringUtil.isNullOrEmpty(cron)) { return null; } try { return new StringBuffer(cron.trim()).toString(); } catch (Exception e) { log.info("执行监测CRON表达式变化任务,刷新定时任务频率,触发器刷新频率转cron异常!e={}", e); } return null; } }
校验表达式是否合法有效参考:
package com.jc.internal.util; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; import org.quartz.CronExpression; public class CronUtil { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入cron表达式:"); // String cron = "0 0 8,20 * * ? *"; // next()方法读取到空白符就结束l;nextLine()读取到回车结束也就是“\r”; String cron = scanner.nextLine(); System.out.println("1、表达式:" + cron); System.out.println("2、是否合法:" + isValid(cron)); System.err.println("3、不合法信息:" + getInvalidMsg(cron)); System.out.println("4、CRON表达式解析:\n" + getExpressionSummary(cron)); Date nextDate = null; System.out.println("5、下一次执行时间:"); for (int i = 0; i < 5; i++) { nextDate = getNextExecution(cron, nextDate); System.out.println(format(nextDate)); } } /** * 判断给定的cron表达式是否有效 * @param cron * @return */ public static boolean isValid(String cron){ return CronExpression.isValidExpression(cron); } /** * 获取cron表达式的无效信息 * @param cron * @return */ public static String getInvalidMsg(String cron){ try { new CronExpression(cron); } catch (ParseException e) { return e.getMessage(); } return ""; } /** * 获取下一次执行时间 * @param cron * @return */ public static Date getNextExecution(String cron, Date currDate){ try { CronExpression ce = new CronExpression(cron); if(currDate == null){ return ce.getNextValidTimeAfter(new Date(System.currentTimeMillis())); }else{ return ce.getNextValidTimeAfter(currDate); } } catch (ParseException e) { throw new IllegalArgumentException(e.getMessage()); } } /** * 格式化日期 * @param date * @return */ public static String format(Date date){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(date); } /** * 解析表达式 * @param cron * @return */ public static String getExpressionSummary(String cron){ try { CronExpression ce = new CronExpression(cron); return ce.getExpressionSummary(); } catch (ParseException e) { throw new IllegalArgumentException(e.getMessage()); } } }
测试结果:
请输入cron表达式:0 0 8,20 * * ? * 1、表达式:0 0 8,20 * * ? * 2、是否合法:true 4、CRON表达式解析: seconds: 0 minutes: 0 hours: 8,20 daysOfMonth: * months: * daysOfWeek: ? lastdayOfWeek: false nearestWeekday: false NthDayOfWeek: 0 lastdayOfMonth: false years: * 5、下一次执行时间: 3、不合法信息: 2021-01-30 20:00:00 2021-01-31 08:00:00 2021-01-31 20:00:00 2021-02-01 08:00:00 2021-02-01 20:00:00
雨淋淋过的季节