可視化定時(shí)任務(wù)quartz集成解析全過(guò)程
前言
在日常的工作中,定時(shí)任務(wù)也是一個(gè)非常常見(jiàn)的需求,可以使用注解實(shí)現(xiàn),但是使用這種方式有幾個(gè)問(wèn)題,首先就是如果修改比較麻煩,而且沒(méi)有提供特定的頁(yè)面對(duì)定時(shí)任務(wù)進(jìn)行可視化管理。所以quartz就應(yīng)運(yùn)而生。本文將介紹如何實(shí)現(xiàn)springboot與quartz的整合。
1.目錄結(jié)構(gòu)
配置類 配置SchedulerFactory固化定時(shí)任務(wù)和日志的業(yè)務(wù)類定時(shí)任務(wù)類運(yùn)行配置
2.原理
- scheduler是一個(gè)計(jì)劃調(diào)度器容器(總部),容器里面可以盛放眾多的JobDetail和trigger,當(dāng)容器啟動(dòng)后,里面的每個(gè)JobDetail都會(huì)根據(jù)trigger按部就班自動(dòng)去執(zhí)行。
- JobDetail是一個(gè)可執(zhí)行的工作,它本身可能是有狀態(tài)的。
- Trigger代表一個(gè)調(diào)度參數(shù)的配置,什么時(shí)候去調(diào)。
- 當(dāng)JobDetail和Trigger在scheduler容器上注冊(cè)后,形成了裝配好的作業(yè)(JobDetail和Trigger所組成的一對(duì)兒),就可以伴隨容器啟動(dòng)而調(diào)度執(zhí)行了。
- scheduler是個(gè)容器,容器中有一個(gè)線程池,用來(lái)并行調(diào)度執(zhí)行每個(gè)作業(yè),這樣可以提高容器效率
3.表結(jié)構(gòu)
自帶有11張系統(tǒng)表和2張業(yè)務(wù)表(自建),其中綠色為自己建立的表
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"); // 延時(shí)啟動(dòng) factory.setStartupDelay(1); factory.setApplicationContextSchedulerContextKey("applicationContextKey"); // 可選,QuartzScheduler // 啟動(dòng)時(shí)更新己存在的Job,這樣就不用每次修改targetObject后刪除qrtz_job_details表對(duì)應(yīng)記錄了 factory.setOverwriteExistingJobs(true); // 設(shè)置自動(dòng)啟動(dòng),默認(rèn)為true factory.setAutoStartup(true); return factory; } }
3.業(yè)務(wù)類
主要是為頁(yè)面提供接口。
@RestController @RequestMapping("/qrtzJob") public class QrtzJobController { @Autowired private QrtzJobService qrtzJobService; /** * 檢查表達(dá)式 * * @param cron * @return */ @GetMapping("/check") public boolean checkCron(String cron) { try { return CronExpression.isValidExpression(cron); } catch (Exception e) { return false; } } /** * 通過(guò)對(duì)象查詢數(shù)據(jù) * * @param qrtzJobVO 請(qǐng)求對(duì)象 * @return 數(shù)據(jù)集合 */ @GetMapping("/selectQrtzJob") @ApiOperation(value = "通過(guò)實(shí)體查詢", notes = "通過(guò)實(shí)體查詢") public Result<List<QrtzJobVO>> selectQrtzJob(@ApiParam(name = "入?yún)?duì)象", value = "實(shí)體", required = false) QrtzJobVO qrtzJobVO) { Result<List<QrtzJobVO>> resultVO = new Result<>(); // 業(yè)務(wù)查詢 List<QrtzJobVO> resultListQrtzJob = qrtzJobService.queryQrtzJobAll(qrtzJobVO); resultVO.setData(resultListQrtzJob); return resultVO; } /** * 通過(guò)對(duì)象增加數(shù)據(jù) * * @param qrtzJobVO 請(qǐng)求對(duì)象 * @return */ @PostMapping("/createQrtzJob") @ApiOperation(value = "通過(guò)實(shí)體添加", notes = "通過(guò)實(shí)體添加") public Result createQrtzJob(@ApiParam(name = "入?yún)?duì)象", value = "實(shí)體", required = false) @RequestBody QrtzJobVO qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務(wù)處理 qrtzJobService.createScheduleJob(qrtzJobVO); return resultVO; } /** * 通過(guò)對(duì)象修改 * * @param qrtzJobVO 請(qǐng)求對(duì)象 * @return */ @PutMapping("/updateQrtzJob") @ApiOperation(value = "通過(guò)實(shí)體修改", notes = "通過(guò)實(shí)體修改") public Result updateQrtzJob(@ApiParam(name = "入?yún)?duì)象", value = "實(shí)體", required = false) @RequestBody QrtzJobVO qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務(wù)處理 qrtzJobService.updateScheduleJob(qrtzJobVO); return resultVO; } /** * 通過(guò)對(duì)象刪除 * * @param qrtzJobVO 請(qǐng)求對(duì)象 * @return */ @DeleteMapping("/deleteQrtzJob") @ApiOperation(value = "通過(guò)實(shí)體刪除", notes = "通過(guò)實(shí)體刪除") public Result deleteQrtzJob(@ApiParam(name = "入?yún)?duì)象", value = "實(shí)體", required = false) @RequestBody QrtzJobVO qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務(wù)處理 qrtzJobService.deleteScheduleJob(qrtzJobVO); return resultVO; } /** * 運(yùn)行定時(shí)任務(wù) * * @param qrtzJobVO * @return */ @GetMapping("/runJob") public Result runJob(@ApiParam(name = "入?yún)?duì)象", value = "實(shí)體", required = false) @RequestBody List<QrtzJobVO> qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務(wù)處理 qrtzJobService.run(qrtzJobVO); return resultVO; } /** * 暫停定時(shí)任務(wù) * * @param qrtzJobVO * @return */ @GetMapping("/pauseJob") public Result pauseJob(@ApiParam(name = "入?yún)?duì)象", value = "實(shí)體", required = false) @RequestBody List<QrtzJobVO> qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務(wù)處理 qrtzJobService.pause(qrtzJobVO); return resultVO; } @GetMapping("resumeJob") public Result resumeJob(@ApiParam(name = "入?yún)?duì)象", value = "實(shí)體", required = false) @RequestBody List<QrtzJobVO> qrtzJobVO) { Result resultVO = new Result(); // 業(yè)務(wù)處理 qrtzJobService.resume(qrtzJobVO); return resultVO; } }
4.運(yùn)行配置
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表達(dá)式失敗", 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)建定時(shí)任務(wù)失敗", 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表達(dá)式失敗"); } 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("更新定時(shí)任務(wù)失敗", 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í)行定時(shí)任務(wù)失敗", e); } } public static void pauseJob(Scheduler scheduler, Long jobId) { try { scheduler.pauseJob(getJobKey(jobId)); } catch (SchedulerException e) { log.error("暫停定時(shí)任務(wù)失敗", e); } } public static void resumeJob(Scheduler scheduler, Long jobId) { try { scheduler.resumeJob(getJobKey(jobId)); } catch (SchedulerException e) { log.error("恢復(fù)定時(shí)任務(wù)失敗", e); } } public static void deleteScheduleJob(Scheduler scheduler, Long jobId) { try { scheduler.deleteJob(getJobKey(jobId)); } catch (SchedulerException e) { log.error("刪除定時(shí)任務(wù)失敗", e); } } }
5.ScheduleJob
用于執(zhí)行定時(shí)任務(wù)。
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("任務(wù)準(zhǔn)備執(zhí)行,任務(wù)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("任務(wù)執(zhí)行完畢,任務(wù)ID:{} 總共耗時(shí):{} 毫秒", scheduleJob.getJobId(), Long.valueOf(times)); } catch (Exception e) { log.error("任務(wù)執(zhí)行失敗,任務(wù)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
通過(guò)反射回去需要調(diào)用的類與方法。
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í)行定時(shí)任務(wù)失敗", e); } } }
5.使用
調(diào)用以上接口 ,參數(shù)如下。
"beanName":"任務(wù)類",
"methodName":"任務(wù)方法",
"params":"參數(shù)",
"cronExpression":"表達(dá)式",
總結(jié)
到此這篇關(guān)于可視化定時(shí)任務(wù)quartz集成解析的文章就介紹到這了,更多相關(guān)quartz集成解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 淺談SpringBoot集成Quartz動(dòng)態(tài)定時(shí)任務(wù)
- SpringBoot與Quartz集成實(shí)現(xiàn)分布式定時(shí)任務(wù)集群的代碼實(shí)例
- SpringBoot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)的方法
- Spring集成Quartz的簡(jiǎn)單配置的方法
- 詳解Quartz 與 Spring框架集成的三種方式
- Spring Boot集成Quartz注入Spring管理的類的方法
- SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)詳解
- SpringBoot2.6.3集成quartz的方式
- Quartz與Spring集成的兩種方法示例
- springBoot項(xiàng)目集成quartz開(kāi)發(fā)定時(shí)任務(wù)案例及注意事項(xiàng)
相關(guān)文章
java中Hutool工具類的常見(jiàn)使用場(chǎng)景詳解
在日常開(kāi)發(fā)中,我們會(huì)使用很多工具類來(lái)提升項(xiàng)目開(kāi)發(fā)的速度,而國(guó)內(nèi)用的比較多的 Hutool 框架,就是其中之一,本文我們就來(lái)介紹一下Hutool的具體使用吧2023-12-12Java多線程中的Exchanger應(yīng)用簡(jiǎn)析
這篇文章主要介紹了Java多線程中的Exchanger應(yīng)用簡(jiǎn)析,Exchanger提供了一個(gè)同步點(diǎn)exchange方法,兩個(gè)線程調(diào)用exchange方法時(shí),無(wú)論調(diào)用時(shí)間先后,兩個(gè)線程會(huì)互相等到線程到達(dá)exchange方法調(diào)用點(diǎn),此時(shí)兩個(gè)線程可以交換數(shù)據(jù),將本線程產(chǎn)出數(shù)據(jù)傳遞給對(duì)方,需要的朋友可以參考下2023-12-12java網(wǎng)上圖書(shū)商城(2)Category模塊
這篇文章主要介紹了java網(wǎng)上圖書(shū)商城,Category模塊,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12SPRINGMVC JSON數(shù)據(jù)交互如何實(shí)現(xiàn)
這篇文章主要介紹了SPRINGMVC JSON數(shù)據(jù)交互如何實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06SpringData JPA實(shí)現(xiàn)查詢分頁(yè)demo
本篇文章主要介紹了SpringData JPA實(shí)現(xiàn)查詢分頁(yè)demo,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03Spring5.2.x 源碼本地環(huán)境搭建的方法步驟
這篇文章主要介紹了Spring5.2.x 源碼本地環(huán)境搭建的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Java如何基于IO流實(shí)現(xiàn)同一文件讀寫(xiě)操作
這篇文章主要介紹了Java如何基于IO流實(shí)現(xiàn)文件讀寫(xiě)操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10