springboot集成quartz,简版-通俗易懂

在网上查询资料,写写删删六七遍还是没怎么搞懂,最后还是写出来了,总结一下,确定是最简单的了。

前言

为什么要使用quartz,而不用springboot的@Scheduled?

因为在日常的业务中,需要经常变换任务的执行时间,即cron的表达式,所以对于@Scheduled用来操作就有些麻烦了,而quartz就很好的可以封装成一个可修改的调用接口,方便业务的多变性


文章导航

  • 前言
  • springboot使用quartz执行任务
    • 思路
    • 添加POM依赖
    • 1. 任务调度器
    • 2. 需要执行的业务任务
    • 3. 启动项目时将quartz也启动
    • cron表达式生成工具类
    • 测试代码

springboot使用quartz执行任务


思路

为什么要说一下思路,因为这个执行的顺序把我搞得很懵,所以只需要将这个思路搞清楚,就很容易的使用quartz的功能了,我简单描述一下我的这个思路

  • 为业务层(eg: service)封装调用quartz的方法,该方法暴露执行的cron表达式(即第一步)

  • 将业务层需要执行的作业放到quartz的执行方法中(即第二步)

  • springboot集成quartz,将quartz任务调度器跟随项目启动而启动起来(即第三步)

    思路理顺了,业务的代码也就知道在哪里写了。


添加POM依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-testartifactId>
    <scope>testscope>
dependency>
<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
dependency>
<dependency>
    <groupId>org.quartz-schedulergroupId>
    <artifactId>quartzartifactId>
dependency>
<dependency>
    <groupId>junitgroupId>
    <artifactId>junitartifactId>
    <version>4.12version>
dependency>

1. 任务调度器

在业务层可以调用这个调度器,使用spring的注入@Autowired

package com.example.springboothtml.scheduler;

import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * 调度器使用
 *
 * @author jiaohongtao
 * @version 1.0
 * @since 2020年11月04日
 */
@Slf4j
@Component
public class QuartzScheduler {

    private static final String JOB_NAME = "inspect_report";
    private static final String JOB_GROUP = "inspect_report_group";
    private static final String TRIGGER_NAME = "inspect_report";
    private static final String TRIGGER_GROUP = "inspect_report_group";
    private static final String JOB_TASK_ID = "job_task_id";

    /**
     * quartz任务调度器
     */
    @Autowired
    private Scheduler scheduler;

    /**
     * 开始执行所有任务,并开启调度器
     *
     * @throws SchedulerException SchedulerException
     */
    public void startJob() throws SchedulerException {
    	// 这里可以放一些初始化的任务,例如服务器宕机后,需要重新启动,如果没有不用考虑这个
    	// 步骤:1.创建一个新的 SchedulerJob 作业类,即第二步的代码
    	// 2.在这个类里写一个方法(invoke())调用新SchedulerJob的作业,然后将方法放到这里
        scheduler.start();
    }

    public void add(int i, String cron) throws SchedulerException {
    	// 构建传递参数
    	JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put(JOB_TASK_ID, id);
        jobDataMap.put("userId", userId);
        
        JobDetail jobDetail = JobBuilder.newJob(InspectReportSchedulerJob.class).usingJobData(jobDataMap).
                withIdentity(JOB_NAME + id, JOB_GROUP).build();
        // 每5s执行一次
        // String cron = "*/5 * * * * ?";
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().
                withIdentity(TRIGGER_NAME + i, TRIGGER_GROUP).withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail, cronTrigger);
    }

    public void remove(int i) throws SchedulerException {
        boolean deleteJob = scheduler.deleteJob(new JobKey(JOB_NAME + i, JOB_GROUP));
        log.info(deleteJob ? "任务移除成功" : "任务移除失败");
    }

    /**
     * 初始注入scheduler
     *
     * @return scheduler
     * @throws SchedulerException SchedulerException
     */
    @Bean
    public Scheduler scheduler() throws SchedulerException {
        SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
        return schedulerFactoryBean.getScheduler();
    }
}

2. 需要执行的业务任务

将需要执行的业务放在放在execute方法中

package com.example.springboothtml.scheduler;

import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

/**
 * @author jiaohongtao
 * @version 1.0
 * @since 2020年11月04日
 */
@Slf4j
public class SchedulerJob implements Job {
    private void before() {
        System.out.println("任务开始执行");
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        before();
        log.info(new Date() + ":我开始执行了......");
        // TODO 业务
        after();
    }

    private void after() {
        System.out.println("任务结束执行");
    }
}

3. 启动项目时将quartz也启动

这个类是在项目启动时,将quartz的任务调度器也拉起来,即第一步的里的方法 — quartzScheduler.startJob()

package com.example.springboothtml.scheduler;

import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;

/**
 * 启动服务后,开启调度器
 *
 * @author jiaohongtao
 * @version 1.0
 * @since 2020年11月04日
 */
@Configuration
public class QuartzStartListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private QuartzScheduler quartzScheduler;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        try {
            quartzScheduler.startJob();
            System.out.println("*******quartz调度器启动*******");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

cron表达式生成工具类

package com.bocloud.inspect.service.util;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * cron表达式生成工具类
 *
 * @author jiaohongtao
 * @version 1.0
 * @since 2020年11月04日
 */
public class CronUtil {

    /**
     * 生成指定格式日期字符
     *
     * @param date       日期
     * @param dateFormat : e.g:yyyy-MM-dd HH:mm:ss
     * @return formatTimeStr
     */
    public static String formatDateByPattern(Date date, String dateFormat) {
        dateFormat = dateFormat == null ? "yyyy-MM-dd HH:mm:ss" : dateFormat;
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        return date != null ? sdf.format(date) : null;
    }

    /**
     * 生成cron表达式 ss mm HH dd MM ? yyyy
     * convert Date to cron ,eg.  "0 06 10 15 1 ? 2014"
     *
     * @param date : 时间点
     */
    public static String getCron(Date date) {
        String dateFormat = "ss mm HH dd MM ? yyyy";
        return formatDateByPattern(date, dateFormat);
    }

    /**
     * 生成cron表达式 ss mm HH dd MM ?
     * convert Date to cron ,eg.  "0 06 10 15 1 ?"
     *
     * @param date : 时间点
     * @param type : 类型 日/周/月
     */
    public static String getLoopCron(Date date, String type, Integer week, Integer day) {
        String dateFormat = "ss mm HH";
        //  dd MM ?
        String cron = formatDateByPattern(date, dateFormat);
        switch (type) {
            case "Day":
                return cron + " * * ?";
            case "Week":
                return cron + " ? * " + getCurrentWeek(week);
            case "Month":
                return cron + " " + day + " * ?";
            default:
                return "false";
        }
    }


    /**
     * 获取当前星期的字符 MON TUE WED THU FRI SAT SUN
     *
     * @param week : 周 1 2 3 4 5 6 7
     * @return 星期字符
     */
    public static String getCurrentWeek(Integer week) {
        String[] weeks = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
        return weeks[week - 1];
    }

    public static void main(String[] args) {
        Date date = new Date();

        String dateFormat = "ss mm HH dd MM ? yyyy";
        String cron = formatDateByPattern(date, dateFormat);
        System.out.println("原始:" + cron);

        String day = formatDateByPattern(date, "ss mm HH");
        System.out.println("日报:" + day + " * * ?");

        // 0 15 10 ? * MON 每周一上午10点15分
        // 动参为 周
        String week = formatDateByPattern(date, "ss mm HH");
        System.out.println("周报:" + week + " ? * MON");

        // 0 15 9 10 * ? 每月10号9点15分
        // 动参为 号
        String month = formatDateByPattern(date, "ss mm HH");
        System.out.println("月报:" + month + " 10 * ?");
    }
}

测试代码

package com.example.springboothtml;

import com.example.springboothtml.scheduler.CronUtil;
import com.example.springboothtml.scheduler.QuartzScheduler;
import org.junit.Test;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author jiaohongtao
 * @version 1.0
 * @since 2020年11月04日
 */
@SpringBootTest
public class QuartzTest {

    @Autowired
    QuartzScheduler quartzScheduler;
    @Test
    public void test1() {
        // Date date = new Date();
        // String time = CronUtil.formatDateByPattern(date, null);
        Date date = null;
        try {
            date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2020-11-04 17:25:30");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        try {
            quartzScheduler.add(1, CronUtil.getCron(date));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

如果有看不懂的部分,请在评论区留言

你可能感兴趣的