Spring Quartz项目实现Job的动态控制


一、简单介绍

Quartz可以对job进行简单控制,但不支持分布式,也没有管理界面和任务分片,但使用起来比较简易。


二、创建简单Demo

我们开始简单使用一下,首先创建Demo,在pom文件中加入以下依赖。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.RELEASE</version>
    <relativePath />
</parent>

<dependencies>
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.3.2</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>
    <!--hutool工具包-->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.5.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.6.3</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>2.5.6</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.19</version>
    </dependency>
</dependencies>

application.yml如下。

server:
  port: 8090
#  servlet:
#    context-path: /

logging:
  level:
    root: info

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&useSSL=false&allowMultiQueries=true
    username: root
    password: 123456
#    driver-class-name: com.mysql.jdbc.Driver
  # 时间格式
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
  quartz:
      job-store-type: jdbc
      initialize-schema: embedded
      #设置自动启动,默认为 true
      auto-startup: true
      #启动时更新己存在的Job
      overwrite-existing-jobs: true
      properties:
        org:
          quartz:
            scheduler:
              instanceName: MyScheduler
              instanceId: AUTO
            jobStore:
              class: org.quartz.impl.jdbcjobstore.JobStoreTX
              driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
              tablePrefix: QRTZ_
              isClustered: true
              misfireThreshold: 60000
              clusterCheckinInterval: 10000
            threadPool:
              class: org.quartz.simpl.SimpleThreadPool
              threadCount: 50
              threadPriority: 5
              threadsInheritContextClassLoaderOfInitializingThread: true

然后创建一个非常简单的Scheduler调度工厂。

@Configuration
public class QuartzConfiguration {
    
    
    /**
     * 注册调度器创建工厂
     */
    @Bean
    public Scheduler schedulerFactoryBean() throws Exception {
    
    
       return StdSchedulerFactory.getDefaultScheduler();
    }
}

添加两个Job Detail,我们要达到的效果是先执行完Job1再执行Job2。两个Job都需要实现Job接口的execute方法,在其中编写业务代码。

@Slf4j
public class TestJob1 implements Job {
    
    
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    
    
        log.info("job1被执行,当前时间:" + new Date());
    }
}
@Slf4j
public class TestJob2 implements Job {
    
    
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    
    
        log.info("job2被执行,当前时间:" + new Date());
    }
}

然后是MVC的分层,这里只写出实现层的代码

@Slf4j
@RequiredArgsConstructor
@Service
public class ServiceImpl implements IService {
    
    

    final Scheduler scheduler;

    @Override
    public String addTask() throws SchedulerException {
    
    
        //创建计划链表
        JobChainingJobListener listener = new JobChainingJobListener("JobLink");

        JobDetail job1 = JobBuilder.newJob(TestJob1.class)
                .withIdentity("job1", "jg1")
                .build();

        JobDetail job2 = JobBuilder.newJob(TestJob2.class)
                .withIdentity("job2", "jg1")
                // 持久存放设置为true,不然Job2只会执行一遍
                .storeDurably(true)
                .build();

        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "tg1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
                .startNow()
                .build();

        scheduler.addJob(job2, false, true);

        //设置执行顺序为先执行Job1再执行Job2
        listener.addJobChainLink(job1.getKey(), job2.getKey());
        //调度器使用计划链表
        scheduler.getListenerManager().addJobListener(listener);
        //安排调度作业
        scheduler.scheduleJob(job1, trigger);
        if (!scheduler.isShutdown()) {
    
    
            scheduler.start();
        }
        return "success";
    }
}

这样启动项目后,请求对应的接口,就可以运行起来了。


三、实现Job的动态操作

1、首先需要创建数据库表。在官网[http://www.quartz-scheduler.org/downloads/]下载项目示例后(我是用的quartz-2.3.0-SNAPSHOT),可以在org.quartz.impl.jdbcjobstore包下找到对应数据库的创建语句。
在这里插入图片描述

2、增加更多的接口,这里展示对应的实现类。

// 创建一个cron的任务
@Override
public void addJob(String clazzName, String jobName, String groupName, String cronExp, Map<String, Object> param) {
    
    
    try {
    
    
        // 启动调度器,默认初始化的时候已经启动
        scheduler.start();
        //构建job信息
        Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(clazzName);
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, groupName).build();
        //表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp);
        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, groupName).withSchedule(scheduleBuilder).build();
        //获得JobDataMap,写入数据
        if (param != null) {
    
    
            trigger.getJobDataMap().putAll(param);
        }
        scheduler.scheduleJob(jobDetail, trigger);
    } catch (Exception e) {
    
    
        log.error("创建任务失败", e);
    }
}

// 暂停任务
@Override
public void pauseJob(String jobName, String groupName) {
    
    
    try {
    
    
        scheduler.pauseJob(JobKey.jobKey(jobName, groupName));
    } catch (SchedulerException e) {
    
    
        log.error("暂停任务失败", e);
    }
}

// 恢复任务
@Override
public void resumeJob(String jobName, String groupName) {
    
    
    try {
    
    
        scheduler.resumeJob(JobKey.jobKey(jobName, groupName));
    } catch (SchedulerException e) {
    
    
        log.error("恢复任务失败", e);
    }
}

// 启动一次
@Override
public void runOnce(String jobName, String groupName) {
    
    
    try {
    
    
        scheduler.triggerJob(JobKey.jobKey(jobName, groupName));
    } catch (SchedulerException e) {
    
    
        log.error("立即运行一次定时任务失败", e);
    }
}

// 更新单个任务
@Override
public void updateJob(String jobName, String groupName, String cronExp, Map<String, Object> param) {
    
    
    try {
    
    
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, groupName);
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        if (cronExp != null) {
    
    
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp);
            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
        }
        //修改map
        if (param != null) {
    
    
            trigger.getJobDataMap().putAll(param);
        }
        // 按新的trigger重新设置job执行
        scheduler.rescheduleJob(triggerKey, trigger);
    } catch (Exception e) {
    
    
        log.error("更新任务失败", e);
    }
}

// 删除单个任务
@Override
public void deleteJob(String jobName, String groupName) {
    
    
    try {
    
    
        //暂停、移除、删除
        scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, groupName));
        scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, groupName));
        scheduler.deleteJob(JobKey.jobKey(jobName, groupName));
    } catch (Exception e) {
    
    
        log.error("删除任务失败", e);
    }
}

// 开启所有的任务
@Override
public void startAllJobs() {
    
    
    try {
    
    
        scheduler.start();
    } catch (Exception e) {
    
    
        log.error("开启所有的任务失败", e);
    }
}

// 暂停所有任务
@Override
public void pauseAllJobs() {
    
    
    try {
    
    
        scheduler.pauseAll();
    } catch (Exception e) {
    
    
        log.error("暂停所有任务失败", e);
    }
}

// 恢复所有任务
@Override
public void resumeAllJobs() {
    
    
    try {
    
    
        scheduler.resumeAll();
    } catch (Exception e) {
    
    
        log.error("恢复所有任务失败", e);
    }
}

// 关闭所有的任务
@Override
public void shutdownAllJobs() {
    
    
    try {
    
    
        if (!scheduler.isShutdown()) {
    
    
            // 需谨慎操作关闭scheduler容器
            // scheduler生命周期结束,无法再 start() 启动scheduler
            scheduler.shutdown(true);
        }
    } catch (Exception e) {
    
    
        log.error("关闭所有的任务失败", e);
    }
}

需要完整Demo可以在此处下载:https://download.csdn.net/download/qq_40579464/87603431

猜你喜欢

转载自blog.csdn.net/qq_40579464/article/details/129708457