Springboot 2.x 整合 quartz 定时任务 实现动态添加、暂停、删除等功能 home 编辑时间 2019/08/20 ![](/api/file/getImage?fileId=5d5f57c416199b2a52001b8d) ## 简介 Springboot 2 整合 quartz 定时任务 (非原创,全文都是参考的简书作者的代码) 记录一下折腾的过程,防止以后忘记 参考:[https://www.jianshu.com/p/b9955ee663b5](https://www.jianshu.com/p/b9955ee663b5) ## 基本代码 ### pom.xml ```xml <!-- quartz --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` ### 数据库 sys_schedule_job ```sql CREATE TABLE `sys_schedule_job` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务id', `job_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '任务名称', `cron_expression` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT 'cron表达式', `bean_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '服务名称', `method_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '方法名称', `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态 0 启动 1 停止', `user_id` int(11) NOT NULL COMMENT '创建人id 关联sys_user', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '软删除标记 0 正常 1 删除', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='定时任务'; ``` ### sys_schedule_job 表对应的类 包括: `SysScheduleJob.java`, `ISysScheduleJobService.java`, `SysScheduleJobServiceImpl.java`, `SysScheduleJobMapper.java`, `SysScheduleJobMapper.xml` (由mybatis plus生成,这里就全部略过了... ) ### 配置 QuartzConfig.java ```java @Configuration public class QuartzConfig { @Bean public SchedulerFactoryBean schedulerFactoryBean(){ SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); //覆盖已存在的任务 schedulerFactoryBean.setOverwriteExistingJobs(true); //延时60秒启动定时任务,避免系统未完全启动却开始执行定时任务的情况 schedulerFactoryBean.setStartupDelay(60); return schedulerFactoryBean; } /** 创建schedule **/ @Bean(name = "scheduler") public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); } } ``` ### 枚举类:JobOperateEnum.java ```java public enum JobOperateEnum { START(0, "启动"), PAUSE(1, "暂停"), DELETE(2, "删除"); private final Integer value; private final String desc; JobOperateEnum(final Integer value, final String desc) { this.value = value; this.desc = desc; } public Serializable getValue() { return this.value; } public String getDesc() { return this.desc; } public String getEnumName() { return name(); } } ``` ### 工厂类:QuartzFactory.java ```java public class QuartzFactory implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取调度数据 SysScheduleJob scheduleJob = (SysScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob"); //获取对应的Bean Object object = SpringUtil.getBean(scheduleJob.getBeanName()); try { //利用反射执行对应方法 Method method = object.getClass().getMethod(scheduleJob.getMethodName()); method.invoke(object); } catch (Exception e) { e.printStackTrace(); } } } ``` ### 服务层 IQuartzService.java ```java public interface IQuartzService { /** * 服务器启动执行定时任务 */ void timingTask(); /** * 新增定时任务 * @param job 任务 */ void addJob(SysScheduleJob job); /** * 操作定时任务 * @param jobOperateEnum 操作枚举 * @param job 任务 */ void operateJob(JobOperateEnum jobOperateEnum, SysScheduleJob job) throws SchedulerException; /** * 启动所有任务 */ void startAllJob() throws SchedulerException; /** * 暂停所有任务 */ void pauseAllJob() throws SchedulerException; } ``` ### 服务层实现类 QuartzServiceImpl.java ```java @Service public class QuartzServiceImpl implements IQuartzService { /** * 调度器 */ @Autowired private Scheduler scheduler; @Autowired private ISysScheduleJobService jobService; @Override public void timingTask() { //查询数据库是否存在需要定时的任务 List<SysScheduleJob> scheduleJobs = jobService.list(); if (scheduleJobs != null) { scheduleJobs.forEach(this::addJob); } } @Override public void addJob(SysScheduleJob job) { try { //创建触发器 Trigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName()) .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())) .startNow() .build(); //创建任务 JobDetail jobDetail = JobBuilder.newJob(QuartzFactory.class) .withIdentity(job.getJobName()) .build(); //传入调度的数据,在QuartzFactory中需要使用 jobDetail.getJobDataMap().put("scheduleJob", job); //调度作业 scheduler.scheduleJob(jobDetail, trigger); } catch (Exception e) { throw new RuntimeException(e); } } @Override public void operateJob(JobOperateEnum jobOperateEnum, SysScheduleJob job) throws SchedulerException { JobKey jobKey = new JobKey(job.getJobName()); JobDetail jobDetail = scheduler.getJobDetail(jobKey); if (jobDetail == null) { //抛异常 } switch (jobOperateEnum) { case START: scheduler.resumeJob(jobKey); break; case PAUSE: scheduler.pauseJob(jobKey); break; case DELETE: scheduler.deleteJob(jobKey); break; } } @Override public void startAllJob() throws SchedulerException { scheduler.start(); } @Override public void pauseAllJob() throws SchedulerException { scheduler.standby(); } } ``` ### JobSchedule.java 实现开机自运行 ```java /** * 实现项目启动后自运行 */ @Component public class JobSchedule implements CommandLineRunner { @Autowired private IQuartzService taskService; /** * 任务调度开始 * @param strings * @throws Exception */ @Override public void run(String... strings) throws Exception { System.out.println("任务调度开始==============任务调度开始"); taskService.timingTask(); System.out.println("任务调度结束==============任务调度结束"); } } ``` ### 目录结构 (除去了sys_schedule_job表用mybatis plus生成的5个文件) ``` ├── quartz │ ├── job │ │ ├── Job.java │ ├── IQuartzService.java │ ├── JobOperateEnum.java │ ├── JobSchedule.java │ ├── QuartzConfig.java │ ├── QuartzFactory.java │ ├── QuartzServiceImpl.java ``` **以上这些都是基本款,具体实现还要加入执行任务方法类和数据库任务数据** ## 功能实现 ### 静态部分 顾名思义,静态部分就是写一个方法,数据库录入一条数据,当项目启动的时候,就会触发定时任务,等到了时间就会运行。 #### Job.java ```java @Component("Job4Log") public class Job { public void test() { System.out.println("-------------------Job4Log任务执行开始-------------------"); System.out.println(new Date().toLocaleString()); System.out.println("-------------------Job4Log任务执行结束-------------------"); } } ``` #### 数据库表 sys_schedule_job id | job_name | cron_expression | bean_name | method_name | status | user_id | create_time | update_time | del_flag -|-|-|-|-|-|-|-|-|- 1 | test job | 0/2 * * * * ? | Job4Log | test | 0 | 1 | 2019-08-21 16:07:53 | 2019-08-21 16:13:44 | 0 #### 效果 ```java -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:20 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:22 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:24 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:26 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:28 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:30 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:32 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:34 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午4:31:36 -------------------Job任务执行结束------------------- ``` ### 动态部分 动态部分就是在静态部分的基础上,加入controller,直接通过接口来实时操作定时任务 #### ScheduleJobController.java ```java @PostMapping("addJob") @ApiOperation("新增定时任务") @Transactional(rollbackFor = Exception.class) public R add(@ApiIgnore @RequestAttribute("sysUser") SysUser user, @RequestBody SysScheduleJobForm form) { SysScheduleJob job = new SysScheduleJob(); job.setJobName(form.getJobName()); job.setCronExpression(form.getCronExpression()); job.setBeanName(form.getBeanName()); job.setMethodName(form.getMethodName()); job.setUserId(user.getId()); job.setStatus(0); jobService.add(job); return R.ok(); } @PostMapping("/startJob") @ApiOperation("启动定时任务") public R start(@RequestBody SysScheduleJobIdForm form) { jobService.start(form.getId()); return R.ok(); } @PostMapping("/pauseJob") @ApiOperation("暂停定时任务") public R pause(@RequestBody SysScheduleJobIdForm form) { jobService.pause(form.getId()); return R.ok(); } @PostMapping("/deleteJob") @ApiOperation("删除定时任务") public R delete(@RequestBody SysScheduleJobIdForm form) { jobService.delete(form.getId()); return R.ok(); } @PostMapping("/startAllJob") @ApiOperation("开始所有定时任务") public R startAllJob() { jobService.startAllJob(); return R.ok(); } @PostMapping("/pauseAllJob") @ApiOperation("暂停所有定时任务") public R pauseAllJob() { jobService.pauseAllJob(); return R.ok(); } ``` #### 效果 调用接口: ``` /scheduleJob/addJob ``` 传入参数: ```json { "beanName": "Job", "cronExpression": "0/2 * * * * ?", "jobName": "test job", "methodName": "test" } ``` 返回参数: ```json { "message": "success", "status": 0 } ``` 控制台输出 ``` -------------------Job任务执行开始------------------- 2019年8月21日 下午5:01:32 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午5:01:34 -------------------Job任务执行结束------------------- -------------------Job任务执行开始------------------- 2019年8月21日 下午5:01:36 -------------------Job任务执行结束------------------- ``` ## CronTrigger配置完整格式: [秒] [分] [小时] [日] [月] [周] [年] ### 参数 1. 秒(0~59) 2. 分钟(0~59) 3. 小时(0~23) 4. 天(0~31,但是你需要考虑你月的天数) 5. 月(0~11) 6. 周(1~7) 7. 年份(1970-2099)(可省略) ### 例子 ```crontab 0 0 0/1 * * ? // 每小时执行一次 0 0 12 * * ? // 每天12点触发 0 0 22 L * ? // 每月最后一天的22点触发 ``` ## END 送人玫瑰,手留余香 赞赏 Wechat Pay Alipay Springboot 2.x 多个 mongodb 数据源 MongoTemplate java springboot 动态生成 sitemap.xml 工具类