SpringBoot 整合 Quartz 实现 对任务进行CRUD

前言

公司之前的项目的定时任务都是使用@Schedule注解进行管理的;新需求需要实现对定时任务进行动态管理。后面决定用Quartz框架进行集成,以最小的代码来管理定时任务。

所需依赖:Springboot  1.xx 或 2.xx-RELEASE 都行, quartz 使用2.3.0版本

        
            org.quartz-scheduler
            quartz
            2.3.0
        

为了简单演示,只创建一个任务类用于修改定时任务实体类即可,创建任务实体类:QuartzBean

@Data
public class QuartzBean implements Serializable {

  private static final long serialVersionUID=1L;

  @TableId
  private String id;
  
  /**
   * 任务名称
   */
  private String jobName;

  /**
   * 任务执行类
   */
  private String jobClass;

  /**
   * 任务时间表达式
   */
  @NotNull
  private String cron;

  /**
   * 任务启动状态 0 运行中 1 已关闭
   */
  private Integer status;

  /**
   * 创建时间
   */
  private Date createTime;
}

一、配置Quartz相关配置类

这里有三个配置类,分别为AutowiringSpringBeanJobFactory.java(主要是为了使得Job任务类运行时,可以注入其他service层)、QuartzConfig.java(quartz配置类,可设置对应的数据源,将schedule创建bean对象等)和 QuartzJobInitializer.java (用于项目启动时,可以从数据库里取出对应的QuartzBean对象,进行任务的自启动)

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

/**
 * 功能说明: job配置可注入其他服务类
 */
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
  private transient AutowireCapableBeanFactory beanFactory;

  @Override
  public void setApplicationContext(ApplicationContext context) {
    beanFactory = context.getAutowireCapableBeanFactory();
  }

  @Override
  protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
    final Object job = super.createJobInstance(bundle);
    beanFactory.autowireBean(job);
    return job;
  }
}


import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;


/**
 * 功能说明: quartz配置类
 */
@Configuration
public class QuartzConfig {


  /** 暂不使用数据库进行quartz的持久化
  @Bean
  public Properties properties() throws IOException {
    PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
    // 对quartz.properties文件进行读取
    propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
    // 在quartz.properties中的属性被读取并注入后再初始化对象
    propertiesFactoryBean.afterPropertiesSet();
    return propertiesFactoryBean.getObject();
  }
   **/

  @Bean
  public AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory() {
    return new AutowiringSpringBeanJobFactory();
  }


  @Bean
  public SchedulerFactoryBean schedulerFactoryBean() {
    SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
    schedulerFactoryBean.setAutoStartup(true);
    schedulerFactoryBean.setJobFactory(autowiringSpringBeanJobFactory());
    // 从application.yml中读取Quartz的配置并设置到SchedulerFactoryBean中
//    schedulerFactoryBean.setQuartzProperties(properties());
    return schedulerFactoryBean;
  }

  /**
   * 通过SchedulerFactoryBean获取Scheduler的实例
   * @param schedulerFactoryBean
   * @return
   */
  @Bean
  public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {
    return schedulerFactoryBean.getScheduler();
  }

}
@Slf4j
@Component
public class QuartzJobInitializer {

  @Autowired
  private Scheduler scheduler;

  @Autowired
  private IQuartzBeanService quartzBeanService;

  @Autowired
  public QuartzJobInitializer(Scheduler scheduler) {
    this.scheduler = scheduler;
  }

  @PostConstruct
  public void init(){
    log.info("quartz:默认启动所有开启状态的定时任务");
    List quartzBeans = quartzBeanService.selectList(new EntityWrapper<>());
    List executeJobs = quartzBeans.stream().filter(f -> QuartzEnums.TaskStatusEnum.RUNNING.getType().equals(f.getStatus())).collect(Collectors.toList());
    try {
      // 这里将会启动所有定时任务
      if (CollUtil.isNotEmpty(executeJobs)) {
        executeJobs.forEach(item -> QuartzUtils.createScheduleJob(scheduler, item));
      }
    }catch (Exception e) {
      log.error("自启动定时任务异常: {}",e);
    }
  }

}

二、创建QuartzUtils.java类

QuartzUtils类主要用于底层的创建、修改、删除、立即执行、暂停和恢复任务

mport com.bean.QuartzBean;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;

/**
 * 功能说明: 定时任务执行工具类
 */
@Slf4j
public class QuartzUtils {

  /**
   * 创建定时任务 定时任务创建之后默认启动状态
   * @param scheduler
   * @param quartzBean
   */
  public static void createScheduleJob(Scheduler scheduler, QuartzBean quartzBean) {
    try {
      //获取到定时任务的执行类  必须是类的绝对路径名称
      //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
      Class jobClass = (Class)Class.forName(quartzBean.getJobClass());
      // 构建定时任务信息
      JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).build();
      // 设置定时任务执行方式
      CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCron());
      // 构建触发器trigger
      CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build();
      scheduler.scheduleJob(jobDetail, trigger);
    } catch (ClassNotFoundException e) {
      log.error("定时任务类路径出错:请输入类的绝对路径 {}",e.getMessage());
    } catch (SchedulerException e) {
      log.error("创建定时任务出错: {}", e.getMessage());
    }
  }

  /**
   * 根据任务名称暂停定时任务
   * @param scheduler
   * @param jobName
   */
  public static void pauseScheduleJob(Scheduler scheduler, String jobName) {
    JobKey jobKey = JobKey.jobKey(jobName);
    try {
      scheduler.pauseJob(jobKey);
    } catch (SchedulerException e) {
      log.error("暂停定时任务出错: {}", e.getMessage());
    }
  }

  /**
   * 根据任务名称恢复定时任务
   * @param scheduler
   * @param jobName
   */
  public static void resumeScheduleJob(Scheduler scheduler, String jobName) {
    JobKey jobKey = JobKey.jobKey(jobName);
    try {
      scheduler.resumeJob(jobKey);
    } catch (SchedulerException e) {
      System.out.println("恢复定时任务出错:"+e.getMessage());
    }
  }

  /**
   * 根据任务名称立即运行一次定时任务
   * @param scheduler
   * @param jobName
   */
  public static void runOnce(Scheduler scheduler, String jobName){
    JobKey jobKey = JobKey.jobKey(jobName);
    try {
      scheduler.triggerJob(jobKey);
    } catch (SchedulerException e) {
      System.out.println("运行定时任务出错:"+e.getMessage());
    }
  }

  /**
   * 更新定时任务
   * @param scheduler
   * @param quartzBean
   */
  public static void updateScheduleJob(Scheduler scheduler, QuartzBean quartzBean)  {
    try {
      //获取到对应任务的触发器
      TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
      //设置定时任务执行方式
      CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCron());
      //重新构建任务的触发器trigger
      CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
      trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
      //重置对应的job
      scheduler.rescheduleJob(triggerKey, trigger);
    } catch (SchedulerException e) {
      System.out.println("更新定时任务出错:"+e.getMessage());
    }
  }

  /**
   * 根据定时任务名称从调度器当中删除定时任务
   * @param scheduler
   * @param jobName
   */
  public static void deleteScheduleJob(Scheduler scheduler, String jobName) {
    JobKey jobKey = JobKey.jobKey(jobName);
    try {
      scheduler.deleteJob(jobKey);
    } catch (SchedulerException e) {
      System.out.println("删除定时任务出错:"+e.getMessage());
    }
  }

}

三、创建任务类,即定时任务可执行的类 MyQuartzTask

import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;

/**
 * 功能说明: 定时任务-MyQuartzTask
 */
@Slf4j
@Service
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class MyQuartzTask extends QuartzJobBean {

  @Override
  protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    String jobName = jobExecutionContext.getJobDetail().getKey().getName();
    log.info("定时任务【{}】启动成功", jobName);
  }

四、效果演示

@Slf4j
@RestController
@RequestMapping("/quartz")
public class QuartzController {

  @Autowired
  private Scheduler scheduler;


  /**
   * 创建定时任务
   * @param quartzVO
   * @return
   */
  @GetMapping("/createScheduleJob")
  public ResultVO createScheduleJob() {
    QuartzBean quartzBean = QuartzBean.builder()
        .jobName("任务名称唯一")
        .jobClass("com.service.impl.quartz.MyQuartzTask")
        .cron("0 0/2 * * * ?")
        .build();
    QuartzUtils.createScheduleJob(scheduler, quartzBean);
    return ResultVOUtil.success();
  }

你可能感兴趣的:(spring,boot,后端,java)