可視化定時任務quartz集成解析全過程
前言
在日常的工作中,定時任務也是一個非常常見的需求,可以使用注解實現(xiàn),但是使用這種方式有幾個問題,首先就是如果修改比較麻煩,而且沒有提供特定的頁面對定時任務進行可視化管理。所以quartz就應運而生。本文將介紹如何實現(xiàn)springboot與quartz的整合。
1.目錄結構
配置類 配置SchedulerFactory固化定時任務和日志的業(yè)務類定時任務類運行配置
2.原理
- scheduler是一個計劃調度器容器(總部),容器里面可以盛放眾多的JobDetail和trigger,當容器啟動后,里面的每個JobDetail都會根據(jù)trigger按部就班自動去執(zhí)行。
- JobDetail是一個可執(zhí)行的工作,它本身可能是有狀態(tài)的。
- Trigger代表一個調度參數(shù)的配置,什么時候去調。
- 當JobDetail和Trigger在scheduler容器上注冊后,形成了裝配好的作業(yè)(JobDetail和Trigger所組成的一對兒),就可以伴隨容器啟動而調度執(zhí)行了。
- scheduler是個容器,容器中有一個線程池,用來并行調度執(zhí)行每個作業(yè),這樣可以提高容器效率
3.表結構
自帶有11張系統(tǒng)表和2張業(yè)務表(自建),其中綠色為自己建立的表
4.整合springboot
1.pom文件
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>
2.ScheduleConfig
配置工廠類的參數(shù)。
@Configuration public class ScheduleConfig { @Bean public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setDataSource(dataSource); // quartz參數(shù) Properties prop = new Properties(); prop.put("org.quartz.scheduler.instanceName", "QUARTZ"); prop.put("org.quartz.scheduler.instanceId", "AUTO"); // 線程池配置 prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); prop.put("org.quartz.threadPool.threadCount", "20"); prop.put("org.quartz.threadPool.threadPriority", "5"); // JobStore配置 prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); // 集群配置 prop.put("org.quartz.jobStore.isClustered", "true"); prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); // sqlserver 啟用 prop.put("org.quartz.jobStore.misfireThreshold", "12000"); prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); factory.setQuartzProperties(prop); factory.setSchedulerName("QUARTZ"); // 延時啟動 factory.setStartupDelay(1); factory.setApplicationContextSchedulerContextKey("applicationContextKey"); // 可選,QuartzScheduler // 啟動時更新己存在的Job,這樣就不用每次修改targetObject后刪除qrtz_job_details表對應記錄了 factory.setOverwriteExistingJobs(true); // 設置自動啟動,默認為true factory.setAutoStartup(true); return factory; } }
3.業(yè)務類
主要是為頁面提供接口。
@RestController @RequestMapping("/qrtzJob") public class QrtzJobController { @Autowired private QrtzJobService qrtzJobService; /** * 檢查表達式 * * @param cron * @return */ @GetMapping("/check") public boolean checkCron(String cron) { try { return CronExpression.isValidExpression(cron); } catch (Exception e) { return false; } } /** * 通過對象查詢數(shù)據(jù) * * @param qrtzJobVO 請求對象 * @return 數(shù)據(jù)集合 */ @GetMapping("/selectQrtzJob") @ApiOperation(value = "通過實體查詢", notes = "通過實體查詢") public Result<List<QrtzJobVO>> selectQrtzJob(@ApiParam(name = "入?yún)ο?, value = "實體", required = false) QrtzJobVO qrtzJobVO) { Result<List<QrtzJobVO>> resultVO = new Result<>(); // 業(yè)務查詢 List<QrtzJobVO> resultListQrtzJob = qrtzJobService.queryQrtzJobAll(qrtzJobVO); resultVO.setData(resultListQrtzJob); return resultVO; } /** * 通過對象增加數(shù)據(jù) * * @param qrtzJobVO 請求對象 * @return */ @PostMapping("/createQrtzJob") @ApiOperation(value = "通過實體添加", notes = "通過實體添加") public Result createQrtzJob(@ApiParam(name = "入?yún)ο?, value = "實體", required = false) @RequestBody QrtzJobVO qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務處理 qrtzJobService.createScheduleJob(qrtzJobVO); return resultVO; } /** * 通過對象修改 * * @param qrtzJobVO 請求對象 * @return */ @PutMapping("/updateQrtzJob") @ApiOperation(value = "通過實體修改", notes = "通過實體修改") public Result updateQrtzJob(@ApiParam(name = "入?yún)ο?, value = "實體", required = false) @RequestBody QrtzJobVO qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務處理 qrtzJobService.updateScheduleJob(qrtzJobVO); return resultVO; } /** * 通過對象刪除 * * @param qrtzJobVO 請求對象 * @return */ @DeleteMapping("/deleteQrtzJob") @ApiOperation(value = "通過實體刪除", notes = "通過實體刪除") public Result deleteQrtzJob(@ApiParam(name = "入?yún)ο?, value = "實體", required = false) @RequestBody QrtzJobVO qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務處理 qrtzJobService.deleteScheduleJob(qrtzJobVO); return resultVO; } /** * 運行定時任務 * * @param qrtzJobVO * @return */ @GetMapping("/runJob") public Result runJob(@ApiParam(name = "入?yún)ο?, value = "實體", required = false) @RequestBody List<QrtzJobVO> qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務處理 qrtzJobService.run(qrtzJobVO); return resultVO; } /** * 暫停定時任務 * * @param qrtzJobVO * @return */ @GetMapping("/pauseJob") public Result pauseJob(@ApiParam(name = "入?yún)ο?, value = "實體", required = false) @RequestBody List<QrtzJobVO> qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務處理 qrtzJobService.pause(qrtzJobVO); return resultVO; } @GetMapping("resumeJob") public Result resumeJob(@ApiParam(name = "入?yún)ο?, value = "實體", required = false) @RequestBody List<QrtzJobVO> qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務處理 qrtzJobService.resume(qrtzJobVO); return resultVO; } }
4.運行配置
ScheduleUtils:將新添加的trigger,jobDetail放入scheduler中。
public class ScheduleUtils { private static final Logger log = LoggerFactory.getLogger(ScheduleUtils.class); private static final String JOB_NAME_PREFIX = "TASK_"; private static TriggerKey getTriggerKey(Long jobId) { return TriggerKey.triggerKey("TASK_" + jobId); } private static JobKey getJobKey(Long jobId) { return JobKey.jobKey("TASK_" + jobId); } public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) { try { return (CronTrigger)scheduler.getTrigger(getTriggerKey(jobId)); } catch (SchedulerException e) { log.error("獲取Cron表達式失敗", e); return null; } } public static void createScheduleJob(Scheduler scheduler, QrtzJobVO scheduleJob) { try { JobDetail jobDetail = JobBuilder.newJob(com.job.util.ScheduleJob.class) .withIdentity(getJobKey(scheduleJob.getJobId())).build(); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) .withMisfireHandlingInstructionDoNothing(); CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger() .withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build(); jobDetail.getJobDataMap().put("JOB_PARAM_KEY", scheduleJob); scheduler.scheduleJob(jobDetail, trigger); if (scheduleJob.getStatus().equals(CommonConstant.QUARTZ_PAUSE)) { pauseJob(scheduler, scheduleJob.getJobId()); } } catch (SchedulerException e) { log.error("創(chuàng)建定時任務失敗", e); } } public static void updateScheduleJob(Scheduler scheduler, QrtzJobVO scheduleJob) { try { TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId()); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) .withMisfireHandlingInstructionDoNothing(); CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId()); if (trigger == null) { throw new SchedulerException("獲取Cron表達式失敗"); } trigger = (CronTrigger)trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); trigger.getJobDataMap().put("JOB_PARAM_KEY", scheduleJob); scheduler.rescheduleJob(triggerKey, trigger); if (scheduleJob.getStatus().equals(CommonConstant.QUARTZ_PAUSE)) { pauseJob(scheduler, scheduleJob.getJobId()); } } catch (SchedulerException e) { log.error("更新定時任務失敗", e); } } public static void run(Scheduler scheduler, QrtzJobVO scheduleJob) { try { JobDataMap dataMap = new JobDataMap(); dataMap.put("JOB_PARAM_KEY", scheduleJob); scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap); } catch (SchedulerException e) { log.error("執(zhí)行定時任務失敗", e); } } public static void pauseJob(Scheduler scheduler, Long jobId) { try { scheduler.pauseJob(getJobKey(jobId)); } catch (SchedulerException e) { log.error("暫停定時任務失敗", e); } } public static void resumeJob(Scheduler scheduler, Long jobId) { try { scheduler.resumeJob(getJobKey(jobId)); } catch (SchedulerException e) { log.error("恢復定時任務失敗", e); } } public static void deleteScheduleJob(Scheduler scheduler, Long jobId) { try { scheduler.deleteJob(getJobKey(jobId)); } catch (SchedulerException e) { log.error("刪除定時任務失敗", e); } } }
5.ScheduleJob
用于執(zhí)行定時任務。
public class ScheduleJob extends QuartzJobBean { private static final Logger log = LoggerFactory.getLogger(ScheduleJob.class); private ExecutorService service = Executors.newSingleThreadExecutor(); @Override protected void executeInternal(JobExecutionContext context) { QrtzJobVO scheduleJob = (QrtzJobVO)context.getMergedJobDataMap().get("JOB_PARAM_KEY"); QrtzJobLogService scheduleJobLogService = (QrtzJobLogService) SpringContextUtil.getBean(QrtzJobLogService.class); QrtzJobLogVO jobLog = new QrtzJobLogVO(); jobLog.setJobId(scheduleJob.getJobId()); jobLog.setBeanName(scheduleJob.getBeanName()); jobLog.setMethodName(scheduleJob.getMethodName()); if (CommonUtil.isEmpty(scheduleJob.getParams())) { jobLog.setParams(""); } else { jobLog.setParams(scheduleJob.getParams()); } long startTime = System.currentTimeMillis(); try { log.info("任務準備執(zhí)行,任務ID:{}", scheduleJob.getJobId()); ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(), scheduleJob.getMethodName(), scheduleJob.getParams()); Future<?> future = this.service.submit(task); future.get(); long times = System.currentTimeMillis() - startTime; jobLog.setTimes(Long.valueOf(times)); jobLog.setStatus("0"); log.info("任務執(zhí)行完畢,任務ID:{} 總共耗時:{} 毫秒", scheduleJob.getJobId(), Long.valueOf(times)); } catch (Exception e) { log.error("任務執(zhí)行失敗,任務ID:" + scheduleJob.getJobId(), e); long times = System.currentTimeMillis() - startTime; jobLog.setTimes(Long.valueOf(times)); jobLog.setStatus("1"); jobLog.setError(StringUtils.substring(e.toString(), 0, 2000)); } finally { scheduleJobLogService.insertQrtzJobLog(jobLog); } } }
6.ScheduleRunnable
通過反射回去需要調用的類與方法。
public class ScheduleRunnable implements Runnable { private static final Logger log = LoggerFactory.getLogger(ScheduleRunnable.class); private Object target; private Method method; private String params; ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException { this.target = SpringContextUtil.getBean(beanName); this.params = params; if (StringUtils.isNotBlank(params)) { this.method = this.target.getClass().getDeclaredMethod(methodName, new Class[] {String.class}); } else { this.method = this.target.getClass().getDeclaredMethod(methodName, new Class[0]); } } @Override public void run() { try { ReflectionUtils.makeAccessible(this.method); if (StringUtils.isNotBlank(this.params)) { this.method.invoke(this.target, new Object[] {this.params}); } else { this.method.invoke(this.target, new Object[0]); } } catch (Exception e) { log.error("執(zhí)行定時任務失敗", e); } } }
5.使用
調用以上接口 ,參數(shù)如下。
"beanName":"任務類",
"methodName":"任務方法",
"params":"參數(shù)",
"cronExpression":"表達式",
總結
到此這篇關于可視化定時任務quartz集成解析的文章就介紹到這了,更多相關quartz集成解析內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- 淺談SpringBoot集成Quartz動態(tài)定時任務
- SpringBoot與Quartz集成實現(xiàn)分布式定時任務集群的代碼實例
- SpringBoot集成Quartz實現(xiàn)定時任務的方法
- Spring集成Quartz的簡單配置的方法
- 詳解Quartz 與 Spring框架集成的三種方式
- Spring Boot集成Quartz注入Spring管理的類的方法
- SpringBoot集成quartz實現(xiàn)定時任務詳解
- SpringBoot2.6.3集成quartz的方式
- Quartz與Spring集成的兩種方法示例
- springBoot項目集成quartz開發(fā)定時任務案例及注意事項
相關文章
SPRINGMVC JSON數(shù)據(jù)交互如何實現(xiàn)
這篇文章主要介紹了SPRINGMVC JSON數(shù)據(jù)交互如何實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06SpringData JPA實現(xiàn)查詢分頁demo
本篇文章主要介紹了SpringData JPA實現(xiàn)查詢分頁demo,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03Spring5.2.x 源碼本地環(huán)境搭建的方法步驟
這篇文章主要介紹了Spring5.2.x 源碼本地環(huán)境搭建的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09