原文链接地址:https://www.jianshu.com/p/b9955ee663b5
说明:
核心框架: SpringBoot 2.1.2
任务调度框架: Quartz 2.3.0
持久层框架: mybatis-plus 3.0.7
数据库:mysql 8.0.12
1.项目目录结构
image.png
2.数据库表结构
DROP TABLE IF EXISTS `schedule_job`; CREATE TABLE `schedule_job` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务id', `job_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务名称', `cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'cron表达式', `bean_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '服务名称', `method_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '方法名称', `status` int(1) NOT NULL DEFAULT 1 COMMENT '状态 1.启动 2.暂停', `delete_flag` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除 0.否 1.是', `creator_id` int(11) NULL DEFAULT NULL COMMENT '创建人id', `creator_name` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', `created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `updated_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
3.pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--Web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Quartz--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <!--Mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> </dependency> <!--Mybatis-Plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.7</version> </dependency> <!--Test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
4.application.yml
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/lanjerry?useUnicode=yes&characterEncoding=UTF8&useSSL=false&serverTimezone=CTT&allowMultiQueries=true username: root password: 123456 hikari: max-lifetime: 1765000 maximum-pool-size: 15 aop: proxy-target-class: true auto: true #mybatis-plus配置 mybatis-plus: global-config: db-config: field-strategy: not_empty id-type: auto db-type: mysql logic-delete-value: 1 logic-not-delete-value: 0 banner: false mapper-locations: classpath:/mapper/*Mapper.xml type-aliases-package: com.example.demo.domain
5.Quartz配置:QuartzConfig.class
@Configuration public class QuartzConfig { @Bean public SchedulerFactoryBean schedulerFactoryBean(){ SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setOverwriteExistingJobs(true);//覆盖已存在的任务 schedulerFactoryBean.setStartupDelay(60);//延时60秒启动定时任务,避免系统未完全启动却开始执行定时任务的情况 return schedulerFactoryBean; } // 创建schedule @Bean(name = "scheduler") public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); } }
6.实体:ScheduleJob.class,枚举:JobOperateEnum
@TableName("schedule_job") public class ScheduleJob implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Integer id; /** * 任务名称 */ private String jobName; /** * cron表达式 */ private String cronExpression; /** * 服务名称 */ private String beanName; /** * 方法名称 */ private String methodName; /** * 状态 1.启动 2.暂停 */ private int status; /** * 是否删除 0.否 1.是 */ @TableField(fill = FieldFill.INSERT) @TableLogic private Boolean deleteFlag; /** * 创建人id */ @TableField(fill = FieldFill.INSERT) private Integer creatorId; /** * 创建人 */ @TableField(fill = FieldFill.INSERT) private String creatorName; /** * 创建时间 */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createdTime; /** * 更新时间 */ @TableField(fill = FieldFill.UPDATE) private LocalDateTime updatedTime; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getJobName() { return jobName; } public void setJobName(String jobName) { this.jobName = jobName; } public String getCronExpression() { return cronExpression; } public void setCronExpression(String cronExpression) { this.cronExpression = cronExpression; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public Boolean getDeleteFlag() { return deleteFlag; } public void setDeleteFlag(Boolean deleteFlag) { this.deleteFlag = deleteFlag; } public Integer getCreatorId() { return creatorId; } public void setCreatorId(Integer creatorId) { this.creatorId = creatorId; } public String getCreatorName() { return creatorName; } public void setCreatorName(String creatorName) { this.creatorName = creatorName; } public LocalDateTime getCreatedTime() { return createdTime; } public void setCreatedTime(LocalDateTime createdTime) { this.createdTime = createdTime; } public LocalDateTime getUpdatedTime() { return updatedTime; } public void setUpdatedTime(LocalDateTime updatedTime) { this.updatedTime = updatedTime; } }
public enum JobOperateEnum { START(1, "启动"), PAUSE(2, "暂停"), DELETE(3, "删除"); 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; } // Jackson 注解为 JsonValue 返回中文 json 描述 public String getDesc() { return this.desc; } public String getEnumName() { return name(); } }
7.任务的调度工厂(主要是实现具体的执行)QuartzFactory.class
public class QuartzFactory implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取调度数据 ScheduleJob scheduleJob = (ScheduleJob) 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(); } } }
8.具体的任务调度以及触发设置:QuartzServiceImpl.class(略过接口)
@Service @Transactional public class QuartzServiceImpl implements QuartzService { /** * 调度器 */ @Autowired private Scheduler scheduler; @Autowired private ScheduleJobService jobService; @Override public void timingTask() { //查询数据库是否存在需要定时的任务 List<ScheduleJob> scheduleJobs = jobService.list(); if (scheduleJobs != null) { scheduleJobs.forEach(this::addJob); } } @Override public void addJob(ScheduleJob 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, ScheduleJob 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(); } }
9.实现CommandLineRunner接口,以达到开机启动执行:JobSchedule.class
@Component public class JobSchedule implements CommandLineRunner { @Autowired private QuartzService taskService; /** * 任务调度开始 * @param strings * @throws Exception */ @Override public void run(String... strings) throws Exception { System.out.println("任务调度开始==============任务调度开始"); taskService.timingTask(); System.out.println("任务调度结束==============任务调度结束"); } }
10.基础的配置完成,以下是几个简单的例子
执行的Job1:
@Component("testJob01") @Transactional public class TestJob01 { public void execute() { System.out.println("-------------------TestJob01任务执行开始-------------------"); System.out.println(new Date()); System.out.println("-------------------TestJob01任务执行结束-------------------"); } }
执行的Job2:
@Component("testJob02") @Transactional public class TestJob02 { public void execute() { System.out.println("-------------------TestJob02任务执行开始-------------------"); System.out.println(new Date()); System.out.println("-------------------TestJob02任务执行结束-------------------"); } }
配置的数据库:
image.png
11.业务类实现:ScheduleJobServiceImpl.class(略过接口)
@Service @Transactional public class ScheduleJobServiceImpl extends ServiceImpl<ScheduleJobMapper, ScheduleJob> implements ScheduleJobService { @Autowired private QuartzService quartzService; @Override public void add(ScheduleJob job) { //此处省去数据验证 this.save(job); //加入job try { quartzService.addJob(job); } catch (Exception e) { e.printStackTrace(); } } @Override public void start(int id) { //此处省去数据验证 ScheduleJob job = this.getById(id); job.setStatus(1); this.updateById(job); //执行job try { quartzService.operateJob(JobOperateEnum.START, job); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void pause(int id) { //此处省去数据验证 ScheduleJob job = this.getById(id); job.setStatus(2); this.updateById(job); //执行job try { quartzService.operateJob(JobOperateEnum.PAUSE, job); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void delete(int id) { //此处省去数据验证 ScheduleJob job = this.getById(id); this.removeById(id); //执行job try { quartzService.operateJob(JobOperateEnum.DELETE, job); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void startAllJob() { //此处省去数据验证 ScheduleJob job = new ScheduleJob(); job.setStatus(1); this.update(job, new QueryWrapper<>()); //执行job try { quartzService.startAllJob(); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void pauseAllJob() { //此处省去数据验证 ScheduleJob job = new ScheduleJob(); job.setStatus(2); this.update(job, new QueryWrapper<>()); //执行job try { quartzService.pauseAllJob(); } catch (SchedulerException e) { e.printStackTrace(); } } }
12.Controller类:ScheduleJobController.class
@RestController @RequestMapping("/job") public class ScheduleJobController { @Autowired private ScheduleJobService jobService; @GetMapping(value = "/hello") public String helloSpringBoot() { return "Hello quartz!"; } @GetMapping("/add") public String add() { ScheduleJob job = new ScheduleJob(); job.setJobName("任务02"); job.setCronExpression("0/2 * * * * ?"); job.setBeanName("testJob02"); job.setMethodName("execute"); jobService.add(job); return "新增定时任务成功"; } @GetMapping("/start/{id}") public String start(@PathVariable("id") Integer id) { jobService.start(id); return "启动定时任务成功"; } @GetMapping("/pause/{id}") public String pause(@PathVariable("id") Integer id) { jobService.pause(id); return "暂停定时任务成功"; } @GetMapping("/delete/{id}") public String delete(@PathVariable("id") Integer id) { jobService.delete(id); return "删除定时任务成功"; } @GetMapping("/startAllJob") public String startAllJob() { jobService.startAllJob(); return "启动所有定时任务成功"; } @GetMapping("/pauseAllJob") public String pauseAllJob() { jobService.pauseAllJob(); return "暂停所有定时任务成功"; } }
使用spring自带的@Scheduled注解实现的定时任务
@Component @EnableScheduling public class SchedulerTask { private int count = 0; @Scheduled(cron = "*/1 * * * * ?") private void process() { System.out.println("this is scheduler task runing " + (count++)); System.out.println("当前时间:" + LocalTime.now()); } }
除了业务层框架mybatis-plus的个别代码没贴出来,关于quartz的全贴出来了,完整源码:
https://gitee.com/lanjerry/quartz-demo
作者:Lanjerry 链接:https://www.jianshu.com/p/b9955ee663b5 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。