总结 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

 

posted @ 2020-11-30 17:13  王晓鸣  阅读(283)  评论(1)    收藏  举报