quartz 可配置的定時服務
阿新 • • 發佈:2019-02-17
一、可配置的定時服務先設計資料庫表結構
二、定義QuartzManager 管理器 可以使得注入可用CREATE TABLE `job` ( `id` CHAR(36) NOT NULL, `name` VARCHAR(36) NOT NULL COMMENT '任務名', `bean_name` VARCHAR(100) NOT NULL COMMENT 'spring bean name', `execute_exp` VARCHAR(200) NOT NULL COMMENT '執行的表示式', `state` INT(11) NOT NULL DEFAULT '1' COMMENT '1有效2無效', `remark` VARCHAR(100) NULL DEFAULT '1' COMMENT '描述資訊', `create_time` DATETIME NOT NULL, PRIMARY KEY (`id`) )
三、定義介面類public class QuartzManager { private static SchedulerFactory sf = null; private static String Default_JOB_GROUP_NAME = "job_group"; private static String Default_TRIGGER_GROUP_NAME = "job_trigger"; static { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = QuartzManager.class.getClassLoader(); } // 載入屬性檔案app.properties InputStream is = null; try { is = classLoader.getResourceAsStream("conf/quartz.properties"); Properties properties = new Properties(); properties.load(is); is.close(); is = null; sf = new StdSchedulerFactory(properties); } catch (Exception e1) { e1.printStackTrace(); } } /** * 新增任務 * * @param jobName * @param triggerName * @param jobClass * @param time * @return * @throws SchedulerException * @throws ParseException */ public static JobDetail addJob(String jobId, String triggerName, String beanName, Class<? extends Job> jobClass, String time) throws SchedulerException, ParseException { Scheduler sched = sf.getScheduler(); JobDetail jobDetail = newJob(jobClass).withIdentity(jobId, Default_JOB_GROUP_NAME).build();// 任務名,任務組,任務執行類 jobDetail.getJobDataMap().put("beanName", beanName); jobDetail.getJobDataMap().put("jobId", jobId); CronTrigger trigger = newTrigger().withIdentity(triggerName, Default_TRIGGER_GROUP_NAME) .withSchedule(cronSchedule(time)).build(); sched.scheduleJob(jobDetail, trigger); if (!sched.isShutdown()) sched.start(); return jobDetail; } public static List<? extends Trigger> getTriggerKeys(JobKey jobKey) throws SchedulerException { return sf.getScheduler().getTriggersOfJob(jobKey); } /** * 觸發一個任務 * * @param jobKey * @throws SchedulerException */ public static void triggerJob(JobKey jobKey) throws SchedulerException { sf.getScheduler().triggerJob(jobKey); } /** * 得到一個觸發器的任務狀態 * * @param triggerKey * @return * @throws SchedulerException */ public static TriggerState getTriggerState(TriggerKey triggerKey) throws SchedulerException { return sf.getScheduler().getTriggerState(triggerKey); } /** * 移除任務 * * @param jobName * @param triggerName * @param jobClass * @param time * @return * @throws SchedulerException * @throws ParseException */ public static void removeJob(JobKey jobKey) throws SchedulerException { Scheduler sched = sf.getScheduler(); sched.pauseJob(jobKey); sched.deleteJob(jobKey); } public static void clearAll() throws SchedulerException { Scheduler sched = sf.getScheduler(); sched.clear(); sched.shutdown(); } }
public interface IQuartzBaseJobService {
public boolean execute(Job job);
}
四、每個新的beanName 實現 IQuartzBaseJobService走自己的邏輯
五、考慮到每個介面只實現,自己的業務不能加日誌等資訊,需要定義一個類來完成這事
六、一般spring 啟動就想執行監聽public class QuartzSpringBeanJob implements org.quartz.Job { private final Logger logger = LoggerFactory.getLogger(QuartzSpringBeanJob.class); @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDetail job = context.getJobDetail(); String jobId = job.getJobDataMap().getString("jobId"); String jobBeanName = job.getJobDataMap().getString("beanName"); if (StringUtils.isEmpty(jobId) || StringUtils.isEmpty(jobBeanName)) { return; } boolean success = true; String message = ""; // 檢查當前job是否可以執行 IJobService jobService = SpringContextHolder.getBean("jobService"); Job jobBean = jobService.findUnique(jobId); if (jobBean == null || jobBean.getState() != BooleanEnum.True.getValue()) { try { QuartzManager.removeJob(job.getKey()); } catch (SchedulerException e) { logger.error(e.getMessage(), e); e.printStackTrace(); } return; } IJobLogService jobLogService = SpringContextHolder.getBean("jobLogService"); // 查詢上一次是否已經執行成功 boolean existsDoing = jobLogService.existsUnComplete(jobId); // 生成job日誌 JobLog jobLog = new JobLog(); jobLog.setId(GuidKeyGenerator.getUUIDKey()); jobLog.setJobId(jobId); jobLog.setStartTime(new Date()); if(!existsDoing){ jobLog.setState(JobLogStateEnum.Doing.getValue()); } else { jobLog.setState(JobLogStateEnum.UnStart.getValue()); jobLog.setMessage("上次未執行結束!本次不再執行!"); } jobLogService.create(jobLog); if(existsDoing){// 還有沒有執行完的,就不再執行了 return ; } try { IQuartzBaseJobService quartzBaseJobService = SpringContextHolder.getBean(jobBeanName);//為自己bean if (quartzBaseJobService != null) { quartzBaseJobService.execute(jobBean); } } catch (Exception e) { success = false; message = e.getMessage(); logger.error(e.getMessage(), e); } // 更新日誌狀態 JobLog newJobLog = new JobLog(); newJobLog.setId(jobLog.getId()); newJobLog.setState(success ? JobLogStateEnum.Success.getValue() : JobLogStateEnum.Error.getValue()); newJobLog.setEndTime(new Date()); newJobLog.setMessage(message); jobLogService.update(newJobLog, jobLog); }
@Service
public class JobTaskService implements IJobTaskService, Initalizer {
private final Logger logger = LoggerFactory.getLogger(JobTaskService.class);
private final static Map<String, JobDetail> jobDetailMap = new HashMap<String, JobDetail>();
@Autowired
private IJobService jobService;
@Autowired
private IJobLogService jobLogService;
@Override
public void initalize() {
jobLogService.clearDoing();
startAll();
}
private void startAll() {
List<Job> jobs = jobService.findValid();
if (jobs == null) return;
for (Job job : jobs) {
try {
JobDetail jobDetail = QuartzManager.addJob(job.getId(), "trigger-" + job.getId(), job.getBeanName(),
QuartzSpringBeanJob.class, job.getExecuteExp());
jobDetailMap.put(job.getId(), jobDetail);
} catch (Exception e) {
e.printStackTrace();
logger.error("addJobError:jobId:" + job.getId() + e.getMessage(), e);
}
}
}
}
七、考慮到新增修改刪除,所以我把我用的方法列public static void removeJob(String jobName) throws SchedulerException{
try {
Scheduler sched = sf.getScheduler();
sched.pauseTrigger(new TriggerKey(jobName, Default_TRIGGER_GROUP_NAME));// 停止觸發器
sched.unscheduleJob(new TriggerKey(jobName, Default_TRIGGER_GROUP_NAME));// 移除觸發器
sched.deleteJob(new JobKey(jobName, Default_JOB_GROUP_NAME));// 刪除任務
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void modifyJobTime(String triggerName,
String triggerGroupName, String time) {
try {
Scheduler sched = sf.getScheduler();
TriggerKey triggerKey = new TriggerKey(triggerName,Default_TRIGGER_GROUP_NAME);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
CronScheduleBuilder scheduleBuilder = cronSchedule(time);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//按新的trigger重新設定job執行
sched.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void clearAll() throws SchedulerException {
Scheduler sched = sf.getScheduler();
sched.clear();
sched.shutdown();
}
<pre name="code" class="java"> /**
* 觸發一個任務
*
* @param jobKey
* @throws SchedulerException
*/
public static void triggerJob(JobKey jobKey) throws SchedulerException {
sf.getScheduler().triggerJob(jobKey);
}
八、總結一下
Trigger 就是個觸發器 jobDetail 就是那個類要作這件事情
scheduler 一個工廠物件返回,作什麼事幾點作就可以了。
scheduler.start();
成了