4.5、动态配置定时任务
从上面的代码中我们可以分析中,定时任务的有三个核心变量,其他的方法都可以封装成公共的。
- 任务名称:例如
myJob
- 任务执行类:例如
TestTask.class
- 任务调度时间:例如
0/5 * * * * ?
基于此规律,我们可以创建一个定时任务实体类,用于保存定时任务相关信息到数据库当中,然后编写一个定时任务工具库,用于创建、更新、删除、暂停任务操作,通过 restful 接口操作将任务存入数据库并管理定时任务!
4.5.1、引入 Jpa 包
<!--jpa 支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!--mysql 数据源--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
在application.properties
中加入数据源配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
4.5.2、创建任务配置表
CREATE TABLE `tb_job_task` ( `id` varchar(50) NOT NULL COMMENT '任务ID', `job_name` varchar(100) DEFAULT NULL COMMENT '任务名称', `job_class` varchar(200) DEFAULT NULL COMMENT '任务执行类', `cron_expression` varchar(50) DEFAULT NULL COMMENT '任务调度时间表达式', `status` int(4) DEFAULT NULL COMMENT '任务状态,0:启动,1:暂停,2:停用', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
4.5.3、编写任务实体类
@Entity @Table(name = "tb_job_task") public class QuartzBean { /** * 任务ID */ @Id private String id; /** * 任务名称 */ @Column(name = "job_name") private String jobName; /** * 任务执行类 */ @Column(name = "job_class") private String jobClass; /** * 任务调度时间表达式 */ @Column(name = "cron_expression") private String cronExpression; /** * 任务状态,0:启动,1:暂停,2:停用 */ @Column(name = "status") private Integer status; //get、set... }
4.5.4、编写任务操作工具类
public class QuartzUtils { private static final Logger log = LoggerFactory.getLogger(QuartzUtils.class); /** * 创建定时任务 定时任务创建之后默认启动状态 * @param scheduler 调度器 * @param quartzBean 定时任务信息类 * @throws Exception */ public static void createScheduleJob(Scheduler scheduler, QuartzBean quartzBean){ try { //获取到定时任务的执行类 必须是类的绝对路径名称 //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。 Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass()); // 构建定时任务信息 JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).build(); // 设置定时任务执行方式 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression()); // 构建触发器trigger CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build(); scheduler.scheduleJob(jobDetail, trigger); } catch (ClassNotFoundException e) { log.error("定时任务类路径出错:请输入类的绝对路径", e); } catch (SchedulerException e) { log.error("创建定时任务出错", e); } } /** * 根据任务名称暂停定时任务 * @param scheduler 调度器 * @param jobName 定时任务名称 * @throws SchedulerException */ public static void pauseScheduleJob(Scheduler scheduler, String jobName){ JobKey jobKey = JobKey.jobKey(jobName); try { scheduler.pauseJob(jobKey); } catch (SchedulerException e) { log.error("暂停定时任务出错", e); } } /** * 根据任务名称恢复定时任务 * @param scheduler 调度器 * @param jobName 定时任务名称 * @throws SchedulerException */ public static void resumeScheduleJob(Scheduler scheduler, String jobName) { JobKey jobKey = JobKey.jobKey(jobName); try { scheduler.resumeJob(jobKey); } catch (SchedulerException e) { log.error("暂停定时任务出错", e); } } /** * 根据任务名称立即运行一次定时任务 * @param scheduler 调度器 * @param jobName 定时任务名称 * @throws SchedulerException */ public static void runOnce(Scheduler scheduler, String jobName){ JobKey jobKey = JobKey.jobKey(jobName); try { scheduler.triggerJob(jobKey); } catch (SchedulerException e) { log.error("运行定时任务出错", e); } } /** * 更新定时任务 * @param scheduler 调度器 * @param quartzBean 定时任务信息类 * @throws SchedulerException */ public static void updateScheduleJob(Scheduler scheduler, QuartzBean quartzBean) { try { //获取到对应任务的触发器 TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName()); //设置定时任务执行方式 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression()); //重新构建任务的触发器trigger CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); //重置对应的job scheduler.rescheduleJob(triggerKey, trigger); } catch (SchedulerException e) { log.error("更新定时任务出错", e); } } /** * 根据定时任务名称从调度器当中删除定时任务 * @param scheduler 调度器 * @param jobName 定时任务名称 * @throws SchedulerException */ public static void deleteScheduleJob(Scheduler scheduler, String jobName) { JobKey jobKey = JobKey.jobKey(jobName); try { scheduler.deleteJob(jobKey); } catch (SchedulerException e) { log.error("删除定时任务出错", e); } } }
4.5.5、编写 Jpa 数据操作服务
public interface QuartzBeanRepository extends JpaRepository<QuartzBean,String> { /** * 修改任务状态 * @param id * @param status */ @Modifying @Transactional @Query("update QuartzBean m set m.status = ?2 where m.id =?1") void updateState(String id, Integer status); /** * 修改任务调度时间 * @param id * @param cronExpression */ @Modifying @Transactional @Query("update QuartzBean m set m.cronExpression = ?2 where m.id =?1") void updateCron(String id, String cronExpression); }
4.5.6、编写controller服务
@RestController @RequestMapping("/quartz") public class QuartzController { private static final Logger log = LoggerFactory.getLogger(QuartzController.class); @Autowired private Scheduler scheduler; @Autowired private QuartzBeanRepository repository; /** * 创建任务 * @param quartzBean */ @RequestMapping("/createJob") public HttpStatus createJob(@RequestBody QuartzBean quartzBean) { log.info("=========开始创建任务========="); QuartzUtils.createScheduleJob(scheduler,quartzBean); repository.save(quartzBean.setId(UUID.randomUUID().toString()).setStatus(0)); log.info("=========创建任务成功,信息:{}", JSON.toJSONString(quartzBean)); return HttpStatus.OK; } /** * 暂停任务 * @param quartzBean */ @RequestMapping("/pauseJob") public HttpStatus pauseJob(@RequestBody QuartzBean quartzBean) { log.info("=========开始暂停任务,请求参数:{}=========", JSON.toJSONString(quartzBean)); QuartzUtils.pauseScheduleJob(scheduler, quartzBean.getJobName()); repository.updateState(quartzBean.getId(), 1); log.info("=========暂停任务成功========="); return HttpStatus.OK; } /** * 立即运行一次定时任务 * @param quartzBean */ @RequestMapping("/runOnce") public HttpStatus runOnce(@RequestBody QuartzBean quartzBean) { log.info("=========立即运行一次定时任务,请求参数:{}", JSON.toJSONString(quartzBean)); QuartzUtils.runOnce(scheduler,quartzBean.getJobName()); log.info("=========立即运行一次定时任务成功========="); return HttpStatus.OK; } /** * 恢复定时任务 * @param quartzBean */ @RequestMapping("/resume") public HttpStatus resume(@RequestBody QuartzBean quartzBean) { log.info("=========恢复定时任务,请求参数:{}", JSON.toJSONString(quartzBean)); QuartzUtils.resumeScheduleJob(scheduler,quartzBean.getJobName()); repository.updateState(quartzBean.getId(), 0); log.info("=========恢复定时任务成功========="); return HttpStatus.OK; } /** * 更新定时任务 * @param quartzBean */ @RequestMapping("/update") public HttpStatus update(@RequestBody QuartzBean quartzBean) { log.info("=========更新定时任务,请求参数:{}", JSON.toJSONString(quartzBean)); QuartzUtils.updateScheduleJob(scheduler,quartzBean); repository.updateCron(quartzBean.getId(), quartzBean.getCronExpression()); log.info("=========更新定时任务成功========="); return HttpStatus.OK; } /** * 删除定时任务 * @param quartzBean */ @RequestMapping("/delete") public HttpStatus delete(@RequestBody QuartzBean quartzBean) { log.info("=========删除定时任务,请求参数:{}", JSON.toJSONString(quartzBean)); QuartzUtils.deleteScheduleJob(scheduler,quartzBean.getJobName()); repository.updateState(quartzBean.getId(), 2); log.info("=========删除定时任务成功========="); return HttpStatus.OK; } }