初步认识动态任务
Quartz定时任务框架经常用于系统后台业务异步处理。平常我们使用时,主要是通过手工编写配置代码文件方式添加修改定时任务,然后重启系统。有时候我们需要根据业务运营需要,动态添加修改定时任务,比如添加新的定时任务、修改任务执行时间、暂停定时任务、删除定时任务等,并且监控定时任务状态,而又不想重启系统,这时就需要系统具备动态管理定时任务的功能。
Quartz提供了一系列组件,支持动态管理定时任务的功能。
主要的实现方法
定时任务管理主要是通过Scheduler的方法来实现。Scheduler提供了一系列方法来管理定时任务的执行状态。主要包括:
addJob():添加定时任务
cornJob():修改定时任务
pauseJob():暂停定时任务执行
resumeJob():恢复定时任务执行
deleteJob():删除定时任务执行
针对上述方法,我们只需要传入对应参数即可。
代码实现
以Springboot整合Quartz为基础
第一步:先在数据库创建一个表(定时任务调度表)
create table t_rb_qrtz_trigger_info(idVARCHAR(20) NOT NULLprimary key,job_name VARCHAR(64) NOT NULL COMMENT '任务名称',job_group VARCHAR(64) NOT NULL COMMENT '任务组名',executor_handler VARCHAR(500) NOT NULL COMMENT '任务执行器',executor_params VARCHAR(50) NULL COMMENT '执行器任务参数',cron_expression VARCHAR(255) NULL COMMENT 'cron执行表达式',misfire_policy VARCHAR(20) default '3' NULL COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',concurrent VARCHAR(1) default '1' NULL COMMENT '是否并发执行(1允许 0禁止)',status VARCHAR(1) default '0' NULL COMMENT '状态(1正常 0暂停)',create_by VARCHAR(64) NULL COMMENT '创建者',create_timeDATETIMENULL COMMENT '创建时间',update_by VARCHAR(64) NULL COMMENT '更新者',update_timeDATETIMENULL COMMENT '更新时间',remark VARCHAR(500) NULL COMMENT '备注信息',constraint t_rb_qrtz_trigger_info_id_uindexunique (id))ENGINE = InnoDB COMMENT '定时任务调度表';
第二步:引入pom依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>3.0.0-SNAPSHOT</version></dependency><dependency><groupId>xyz.riceball</groupId><artifactId>riceball-framework</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
第三步:建好实体类:
@Data@TableName("t_rb_qrtz_trigger_info")public class JobInfoPO extends BaseDatePO {private String id;private String jobName;private String jobGroup;private String executorHandler;private String executorParams;private String cronExpression;private String misfirePolicy;private String concurrent;private String status;private String createBy;private LocalDateTime createTime;private String updateBy;private LocalDateTime updateTime;private String remark;}
第四步:编写mapper
@Mapperpublic interface JobInfoMapper extends BaseMapper<JobInfoPO> {}
第五步:编写service文件
@Service@Slf4jpublic class JobServiceImpl extends ServiceImpl<JobInfoMapper, JobInfoPO> implements JobService {@Resourceprivate Scheduler scheduler;@Overridepublic JobInfoPO addJob(JobDto jobDto) {QuartzJobBean quartzJobBean = JobUtils.getClass(jobDto.getExecutorHandler());//执行参数String executorParams = jobDto.getExecutorParams();JobDataMap jobDataMap = JSONUtil.toBean(executorParams, JobDataMap.class);JobDetail jobDetail = JobBuilder.newJob(quartzJobBean.getClass()).withIdentity(jobDto.getJobName(), jobDto.getJobGroup()).usingJobData(jobDataMap).build();// Cron表达式调度构建器(即任务执行的时间)CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(jobDto.getCronExpression());//根据Cron表达式构建一个TriggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobDto.getJobName(), jobDto.getJobGroup()).withSchedule(cron).build();try {scheduler.scheduleJob(jobDetail, trigger);scheduler.start();} catch (SchedulerException e) {log.error("【定时任务】创建失败!", e);throw new RuntimeException("【定时任务】创建失败!");}log.info("新增任务成功");JobInfoPO jobInfoPO = new JobInfoPO();BeanUtils.copyWithoutNull(jobInfoPO, jobDto);jobInfoPO.setStatus(ENBool.TRUE.getValue());BeanUtils.buildAutoField(jobInfoPO, true, "super");int count = getBaseMapper().insert(jobInfoPO);if (count==1) {log.info("新增任务,修改数据库成功");}else {log.error("新增任务,修改数据库失败");}return jobInfoPO;}@Overridepublic void deleteJob(JobDto jobDto) {TriggerKey triggerKey = TriggerKey.triggerKey(jobDto.getJobName(), jobDto.getJobGroup());JobKey jobKey = JobKey.jobKey(jobDto.getJobName(), jobDto.getJobGroup());try {scheduler.pauseTrigger(triggerKey);scheduler.unscheduleJob(triggerKey);scheduler.deleteJob(jobKey);} catch (SchedulerException e) {log.error("删除任务失败", e);throw new RuntimeException("删除任务失败");}log.info("删除任务成功");int count = getBaseMapper().deleteById(jobDto.getId());if (count==1){log.info("删除任务,修改数据库成功");}else {log.error("删除任务,修改数据库失败");}}@Overridepublic void pauseJob(JobDto jobDto) {try {scheduler.pauseJob(JobKey.jobKey(jobDto.getJobName(), jobDto.getJobGroup()));} catch (SchedulerException e) {throw new RuntimeException(e);}log.info("停止任务成功");JobInfoPO jobInfoPO = getBaseMapper().selectById(jobDto.getId());jobInfoPO.setStatus(ENBool.FALSE.getValue());BeanUtils.buildAutoField(jobInfoPO, false, "super");int count = getBaseMapper().updateById(jobInfoPO);if (count==1) {log.info("停止任务,修改数据库成功");}else {log.error("停止任务,修改数据库失败");}}@Overridepublic void resumeJob(JobDto jobDto) {try {scheduler.resumeJob(JobKey.jobKey(jobDto.getJobName(), jobDto.getJobGroup()));} catch (SchedulerException e) {throw new RuntimeException(e);}log.info("重启任务成功");JobInfoPO jobInfoPO = getBaseMapper().selectById(jobDto.getId());jobInfoPO.setStatus(ENBool.TRUE.getValue());BeanUtils.buildAutoField(jobInfoPO, false, "super");int count = getBaseMapper().updateById(jobInfoPO);if (count==1) {log.info("停止任务,修改数据库成功");}else {log.error("停止任务,修改数据库失败");}}@Overridepublic void cornJob(JobDto jobDto) {TriggerKey triggerKey = TriggerKey.triggerKey(jobDto.getJobName(), jobDto.getJobGroup());// 表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobDto.getCronExpression());CronTrigger trigger = null;try {trigger = (CronTrigger) scheduler.getTrigger(triggerKey);// 根据Cron表达式构建一个Triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).startNow().build();// 按新的trigger重新设置job执行scheduler.rescheduleJob(triggerKey, trigger);} catch (SchedulerException e) {throw new RuntimeException(e);}log.info("修改任务corn成功");JobInfoPO jobInfoPO = getBaseMapper().selectById(jobDto.getId());jobInfoPO.setCronExpression(jobDto.getCronExpression());BeanUtils.buildAutoField(jobInfoPO, false, "super");int count = getBaseMapper().updateById(jobInfoPO);if (count==1) {log.info("修改任务corn表达式,修改数据库成功");}else {log.error("修改任务corn表达式,修改数据库失败");}}}
第六步:编写controller
@RestController@RequestMapping("/job")public class JobController {@Resourceprivate JobService jobService;@PostMappingpublic ApiR addJob(@RequestBody JobDto jobDto) {JobInfoPO jobInfoPO = jobService.addJob(jobDto);return ApiR.okMsgAndData("新增成功",jobInfoPO);}@DeleteMappingpublic ApiR deleteJob(@RequestBody JobDto jobDto) {jobService.deleteJob(jobDto);return ApiR.ok();}@PostMapping("pause")public ApiR pauseJob(@RequestBody JobDto jobDto) {jobService.pauseJob(jobDto);return ApiR.ok();}@PostMapping("resume")public ApiR resumeJob(@RequestBody JobDto jobDto) {jobService.resumeJob(jobDto);return ApiR.ok();}@PutMappingpublic ApiR cornJob(@RequestBody JobDto jobDto) {jobService.cornJob(jobDto);return ApiR.ok();}@GetMappingpublic ApiR listAll() {List<JobInfoPO> jobInfoPOS = jobService.list();return ApiR.okMsgAndData("成功", jobInfoPOS);}}