package cn.hmsoft.frame.timer; import java.time.LocalDateTime; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.quartz.CronExpression; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.Job; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.SchedulerFactory; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import cn.hmsoft.frame.constants.FrameParamConstants; import cn.hmsoft.frame.constants.FrameStatus; import cn.hmsoft.frame.data.dao.FrameTimerDao; import cn.hmsoft.frame.data.model.FrameTimer; import cn.hmsoft.helper.DateHelper; import cn.hmsoft.helper.LogHelper; import cn.hmsoft.helper.StringHelper; import cn.hmsoft.web.config.SpringConfig; /************************* * 系统定时器辅助类 * * @author zxq * @create 2018-05-10 15:31:38 * @version 5.0.0 * @email: revisit@126.com * @Company: www.hmsoft.cn */ public final class FrameTimerUtil { private final static String JobGroupName = "HmSoftJobGroup"; private final static String JobNameStartWith = "HmSoftJobName"; public final static String TimerJobParamName = "TimerJobParamName"; private static SchedulerFactory JobSchedulerFactory = null; private static Map TimerMap = null; /********************* * 系统定时器模块是否正常启用 */ private static boolean FrameTimerStatus = false; /*************************** * 数据库是否可用 */ private static boolean TimerDatabaseFlag = false; /************************************************* * 设置基本参数 */ static { synchronized (FrameTimerUtil.class) { if (JobSchedulerFactory == null) { Properties p = new Properties(); // 表明scheduler的主线程是否为守护线程 p.setProperty("org.quartz.scheduler.makeSchedulerThreadDaemon", TimerModuleConfig.FrameTimerThreadDaemon); // 使用ThreadPool的实现的名字。Quartz自带的线程池是“org.quartz.simpl.SimpleThreadPool”,几乎满足所有用户的需求。它的行为很简单,测试的也很好。它提供了固定大小的线程池,生命周期与Scheduler相同。 p.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); // 可以是任意的正整数。实际上只有1到100会用到。这是并行执行job可用的线程数。如果只有几个job,一天也只有几次触发,那么一个线程就足够了!如果有成百上千的job,且每一个每一分钟都会触发。那么可能想要让线程的数量达到50或者100了。 p.setProperty("org.quartz.threadPool.threadCount", "" + TimerModuleConfig.FrameTimerThreadCount); // 可以设为true,那么线程池中创建的线程都是守护线程。默认为false p.setProperty("org.quartz.threadPool.makeThreadsDaemons", TimerModuleConfig.FrameTimerThreadDaemon); TimerMap = new LinkedHashMap(); try { // 启动任务池 JobSchedulerFactory = new StdSchedulerFactory(p); JobSchedulerFactory.getScheduler().start(); FrameTimerStatus = true; } catch (Exception e) { LogHelper.error("frame timer module load error , please check quartz's file"); } } } } private static FrameTimerUtil util = null; private FrameTimerUtil() { TimerMap = new LinkedHashMap(); } public static FrameTimerUtil getInstance() { if (util == null) { synchronized (FrameTimerUtil.class) { if (util == null) util = new FrameTimerUtil(); // 只有正常初始quartz之后,以下操作才有意义 if (FrameTimerStatus == true) { List timerArray = SpringConfig.getBean(FrameTimerDao.class) .listTimer(FrameParamConstants.AppName); for (FrameTimer timer : timerArray) { util.initTimer(timer); } } } } return util; } /************************ * 启动一个定时器 */ public boolean initTimer(FrameTimer timer) { if (!timer.getTimer_status().equals(FrameStatus.Active.toString()) || (timer.getTimer_end_time() != null && timer.getTimer_end_time().isBefore(LocalDateTime.now()))) return false; String timer_cron = timer.getTimer_cron(); if (StringHelper.isEmpty(timer_cron)) { // 一次性任务,直接运行 FrameTimerConfig config = null; try { config = (FrameTimerConfig) Class.forName(timer.getTimer_class()).newInstance(); } catch (Exception e) { // 不是FrameTimerConfig子类,无法正常初始化 LogHelper.error( "frame timer [" + timer.getTimer_name() + "] timer_class instanct fail,please check code !"); return false; } timer.prepareParamMap(); // 直接执行.. try { config.execute(timer); return true; } catch (Exception e) { LogHelper.log(e); return false; } } else { // 定时任务 // 判断表达式是否正确 if (!CronExpression.isValidExpression(timer_cron)) { LogHelper.error("frame timer [" + timer.getTimer_name() + "],cron expression [" + timer.getTimer_cron() + "] is error !"); return false; } // 初始化JOB try { JobKey key = new JobKey(JobNameStartWith + timer.getTimer_id(), JobGroupName); @SuppressWarnings("unchecked") JobDetail jobDetail = JobBuilder.newJob((Class) Class.forName(timer.getTimer_class())) .withIdentity(key).build(); jobDetail.getJobDataMap().put(TimerJobParamName, timer); LocalDateTime start_time = timer.getTimer_start_time(), end_time = timer.getTimer_end_time(); // 没有配置结束时间,加30年 if (end_time == null) end_time = LocalDateTime.now().plusYears(30); // 如果没有开始时间,10秒后开始 if (start_time == null) start_time = LocalDateTime.now().plusSeconds(10); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(JobNameStartWith + timer.getTimer_id(), JobGroupName) .withSchedule(CronScheduleBuilder.cronSchedule(timer_cron)) .startAt(DateHelper.toDate(start_time)).endAt(DateHelper.toDate(end_time)).build(); JobSchedulerFactory.getScheduler().scheduleJob(jobDetail, trigger); if (trigger.getNextFireTime() != null) timer.setTimer_next_time(DateHelper.toLocalDateTime(trigger.getNextFireTime())); // 如果数据库可用,更新数据库 if (TimerDatabaseFlag) SpringConfig.GobalDao.update(timer); LogHelper.info("frame timer [" + timer.getTimer_name() + "] init:" + timer.getTimer_class()); TimerMap.put(timer.getTimer_id(), timer); // 如果是自动启动,马上进行调度 if (timer.getAuto_run_flag().equals(FrameStatus.Active.toString())) JobSchedulerFactory.getScheduler().triggerJob(key); } catch (Exception e) { LogHelper.error(e); return false; } } return true; } public boolean shutdown() { try { JobSchedulerFactory.getScheduler().shutdown(); return true; } catch (Exception e) { LogHelper.error(e); return false; } } }