Spring Boot入门教程(二十六): 定时任务

一:简介

定时任务分为静态定时任务和动态定时任务

  • 静态定时任务::依赖于spring-context,静态定时任务将定时时间直接使用注解@Scheduled注解到要定时的方法上,绑定过于耦合,一旦应用启动定时任务就开始了,中间要想更改定时任务(如更改定时时间、更改定时任务相应的逻辑调整等)必须停止服务,手动更改代码重新部署才可,静态定时任务通常用于实现简单的定时任务计划

  • 动态定时任务:依赖于spring-boot-starter-quartz,动态定时任务可以通过一套增删改查将要执行的定时代码和定时时间配置到数据库中,这样可以动态的创建定时任务、更新任务、执行任务、暂停任务、继续执行任务、删除任务操作,这些操作是静态定时任务无法实现的,动态定时任务更加灵活


二:静态定时任务

1. pom.xml

静态定时任务会使用到spring-context中的@Scheduled和@EnableScheduling注解,所以不需要特别引入什么依赖,一般很多依赖中都会间接引用到,如spring-boot-starter-web也会间接引用spring-context

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. job

@Component
public class StaticJob {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final static long SECOND = 1000;


    /**
     * fixedDelay: 固定延迟时间执行
     */
    @Scheduled(fixedDelay = 10 * SECOND)
    public void fixedDelayJob() {
        logger.info("------------------{}\tfixedDelay", System.currentTimeMillis());
    }

    /**
     * fixedRate: 固定间隔时间执行
     */
    @Scheduled(fixedRate = 10 * SECOND)
    public void fixedRate() {
        logger.info("------------------{}\tfixedRate", System.currentTimeMillis());
    }

    /**
     * cron: 通过 Cron 表达式控制执行
     */
    @Scheduled(cron = "*/10 * * * * ?")
    public void cron() {
        logger.info("------------------{}\tcron", System.currentTimeMillis());
    }
}

3. 开启定时任务@EnableScheduling

@SpringBootApplication
@EnableScheduling
public class SchedulingApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActuatorApplication.class, args);
    }
}

4. run

这里写图片描述


三:动态定时任务

这里写图片描述

1. pom.xml

动态定时任务是使用的spring-boot-starter-quartz

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

2. application.properties

# DataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root123
spring.datasource.platform=mysql
spring.datasource.initialization-mode=embedded
spring.datasource.schema=classpath:schema/schema-${spring.datasource.platform}.sql


mybatis.type-aliases-package=com.example.quartz.domain
mybatis.mapper-locations=mappers/**Mapper.xml

3. sql

src/main/resources/schema/schema-mysql.sql 如下,同时还需要手动在test数据库上执行这些sql,创建quartz相应的表结构

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
    IS_DURABLE VARCHAR(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    NEXT_FIRE_TIME BIGINT(13) NULL,
    PREV_FIRE_TIME BIGINT(13) NULL,
    PRIORITY INTEGER NULL,
    TRIGGER_STATE VARCHAR(16) NOT NULL,
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
    START_TIME BIGINT(13) NOT NULL,
    END_TIME BIGINT(13) NULL,
    CALENDAR_NAME VARCHAR(200) NULL,
    MISFIRE_INSTR SMALLINT(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    REPEAT_COUNT BIGINT(7) NOT NULL,
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    CRON_EXPRESSION VARCHAR(200) NOT NULL,
    TIME_ZONE_ID VARCHAR(80),
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    BLOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    CALENDAR_NAME  VARCHAR(200) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_GROUP  VARCHAR(200) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    ENTRY_ID VARCHAR(95) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    FIRED_TIME BIGINT(13) NOT NULL,
    SCHED_TIME BIGINT(13) NOT NULL,
    PRIORITY INTEGER NOT NULL,
    STATE VARCHAR(16) NOT NULL,
    JOB_NAME VARCHAR(200) NULL,
    JOB_GROUP VARCHAR(200) NULL,
    IS_NONCONCURRENT VARCHAR(1) NULL,
    REQUESTS_RECOVERY VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    LOCK_NAME  VARCHAR(40) NOT NULL,
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);


DROP TABLE IF EXISTS schedule_job;

CREATE TABLE schedule_job (
  id               INT       AUTO_INCREMENT,
  class_name       VARCHAR(200),
  cron_expression  VARCHAR(50),
  job_name         VARCHAR(100),
  job_group        VARCHAR(100),
  trigger_name     VARCHAR(100),
  trigger_group    VARCHAR(100),
  pause            BOOLEAN   DEFAULT FALSE,
  enable           BOOLEAN   DEFAULT TRUE,
  description      VARCHAR(500),
  create_time      TIMESTAMP DEFAULT current_timestamp,
  last_update_time TIMESTAMP DEFAULT current_timestamp ON UPDATE current_timestamp,
  CONSTRAINT PRIMARY KEY pk_schedule_job_id (id)
);

CREATE INDEX i_schedule_job_id  ON schedule_job (id);

这里写图片描述

4. domain

public class ScheduleJob implements Serializable {
    private Long id;

    private String className;

    private String cronExpression;

    private String jobName;

    private String jobGroup;

    private String triggerName;

    private String triggerGroup;

    private Boolean pause;

    private Boolean enable;

    private String description;

    private Date createTime;

    private Date lastUpdateTime;

    // Getter & Setter

5. dao

@Mapper
public interface JobDao {
    ScheduleJob select(@Param("id") long id);

    Integer update(ScheduleJob scheduleJob);

    Integer insert(ScheduleJob scheduleJob);

    Integer delete(Long productId);

    List<ScheduleJob> getAllJob();

    List<ScheduleJob> getAllEnableJob();
}

src/main/resources/mappers/JobMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.quartz.dao.JobDao">

    <sql id="baseColumnSql">
        id, class_name, cron_expression, job_name, job_group, trigger_name, trigger_group, pause,
        enable, description, create_time, last_update_time
    </sql>

    <resultMap id="baseResultMap" type="ScheduleJob">
        <id column="id" property="id" javaType="java.lang.Long" jdbcType="INTEGER"></id>
        <result column="class_name" property="className" javaType="java.lang.String" jdbcType="VARCHAR"></result>
        <result column="cron_expression" property="cronExpression" javaType="java.lang.String" jdbcType="VARCHAR"></result>
        <result column="job_name" property="jobName" javaType="java.lang.String" jdbcType="VARCHAR"></result>
        <result column="job_group" property="jobGroup" javaType="java.lang.String" jdbcType="VARCHAR"></result>
        <result column="trigger_name" property="triggerName" javaType="java.lang.String" jdbcType="VARCHAR"></result>
        <result column="trigger_group" property="triggerGroup" javaType="java.lang.String" jdbcType="VARCHAR"></result>
        <result column="pause" property="pause" javaType="java.lang.Boolean" jdbcType="BOOLEAN"></result>
        <result column="enable" property="enable" javaType="java.lang.Boolean" jdbcType="BOOLEAN"></result>
        <result column="description" property="description" javaType="java.lang.String" jdbcType="VARCHAR"></result>
        <result column="create_time" property="createTime" javaType="java.util.Date" jdbcType="TIMESTAMP"></result>
        <result column="last_update_time" property="lastUpdateTime" javaType="java.util.Date" jdbcType="TIMESTAMP"></result>
    </resultMap>

    <select id="select" resultMap="baseResultMap">
        SELECT
        <include refid="baseColumnSql"/>
        FROM schedule_job
        WHERE id = #{id}
    </select>

    <select id="getAllJob" resultMap="baseResultMap">
        SELECT
        <include refid="baseColumnSql"/>
        FROM schedule_job
    </select>

    <select id="getAllEnableJob" resultMap="baseResultMap">
        SELECT
        <include refid="baseColumnSql"/>
        FROM schedule_job
        WHERE enable = TRUE
    </select>

    <update id="update" parameterType="ScheduleJob" flushCache="true">
        UPDATE schedule_job
        <set>
            <if test="className != null ">
                class_name = #{className},
            </if>
            <if test="cronExpression != null ">
                cron_expression = #{cronExpression},
            </if>
            <if test="jobName != null ">
                job_name = #{jobName},
            </if>
            <if test="jobGroup != null ">
                job_group = #{jobGroup},
            </if>
            <if test="triggerName != null ">
                trigger_name = #{triggerName},
            </if>
            <if test="triggerGroup != null ">
                trigger_group = #{triggerGroup},
            </if>
            <if test="pause != null ">
                pause = #{pause},
            </if>
            <if test="enable != null ">
                enable = #{enable},
            </if>
            <if test="description != null ">
                description = #{description},
            </if>
        </set>
        WHERE id = #{id}
    </update>

    <delete id="delete" parameterType="java.lang.Long">
        UPDATE schedule_job
        SET enable = FALSE
        WHERE id = #{id}
    </delete>

    <insert id="insert" parameterType="ScheduleJob" keyProperty="id" useGeneratedKeys="true">
        INSERT INTO schedule_job
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="className != null ">
                class_name,
            </if>
            <if test="cronExpression != null ">
                cron_expression,
            </if>
            <if test="jobName != null ">
                job_name,
            </if>
            <if test="jobGroup != null ">
                job_group,
            </if>
            <if test="triggerName != null ">
                trigger_name,
            </if>
            <if test="triggerGroup != null ">
                trigger_group,
            </if>
            <if test="pause != null ">
                pause,
            </if>
            <if test="enable != null ">
                enable,
            </if>
            <if test="description != null ">
                description,
            </if>
        </trim>
        <trim prefix=" VALUES (" suffix=")" suffixOverrides=",">
            <if test="className != null ">
                #{className},
            </if>
            <if test="cronExpression != null ">
                #{cronExpression},
            </if>
            <if test="jobName != null ">
                #{jobName},
            </if>
            <if test="jobGroup != null ">
                #{jobGroup},
            </if>
            <if test="triggerName != null ">
                #{triggerName},
            </if>
            <if test="triggerGroup != null ">
                #{triggerGroup},
            </if>
            <if test="pause != null ">
                #{pause},
            </if>
            <if test="enable != null ">
                #{enable},
            </if>
            <if test="description != null ">
                #{description},
            </if>
        </trim>
    </insert>
</mapper>

6. exception

public class ServiceException extends Exception {

    public ServiceException(String msg, Exception e) {
        super(msg + "\n" + e.getMessage());
    }

    public ServiceException(String msg) {
        super(msg);
    }
}

7. service

@Service
public class JobService {

    @Autowired
    private JobDao jobDao;

    @Autowired
    private Scheduler scheduler;

    private final Logger logger = LoggerFactory.getLogger(getClass());

    public List<ScheduleJob> getAllEnableJob() {
        return jobDao.getAllEnableJob();
    }

    public ScheduleJob select(Long jobId) throws ServiceException {
        ScheduleJob scheduleJob = jobDao.select(jobId);
        if (scheduleJob == null) {
            throw new ServiceException("ScheduleJob:" + jobId + " not found");
        }
        return scheduleJob;
    }

    @Transactional(rollbackFor = DataAccessException.class)
    public ScheduleJob update(Long jobId, ScheduleJob scheduleJob) throws ServiceException {

        if (jobDao.update(scheduleJob) <= 0) {
            throw new ServiceException("Update product:" + jobId + "failed");
        }

        ScheduleUtil.updateScheduleJob(scheduler, scheduleJob);

        return scheduleJob;
    }

    @Transactional(rollbackFor = DataAccessException.class)
    public boolean add(ScheduleJob scheduleJob) throws ServiceException {
        Integer num = jobDao.insert(scheduleJob);
        if (num <= 0) {
            throw new ServiceException("Add product failed");
        }

        ScheduleUtil.createScheduleJob(scheduler, scheduleJob);

        return true;
    }

    @Transactional(rollbackFor = DataAccessException.class)
    public boolean delete(Long jobId) throws ServiceException {
        ScheduleJob scheduleJob = select(jobId);

        Integer num = jobDao.delete(jobId);
        if (num <= 0) {
            throw new ServiceException("Delete product:" + jobId + "failed");
        }

        ScheduleUtil.deleteJob(scheduler, scheduleJob);

        return true;
    }

    public List<ScheduleJob> getAllJob() {
        return jobDao.getAllJob();
    }

    public boolean resume(Long jobId) throws ServiceException {
        ScheduleJob scheduleJob = updateScheduleJobStatus(jobId, false);
        ScheduleUtil.resumeJob(scheduler, scheduleJob);
        return true;
    }

    public boolean pause(Long jobId) throws ServiceException {
        ScheduleJob scheduleJob = updateScheduleJobStatus(jobId, true);
        ScheduleUtil.pauseJob(scheduler, scheduleJob);
        return true;
    }

    public boolean run(Long jobId) throws ServiceException {
        ScheduleJob scheduleJob = updateScheduleJobStatus(jobId, false);
        ScheduleUtil.run(scheduler, scheduleJob);
        return true;
    }


    private ScheduleJob updateScheduleJobStatus(Long jobId, Boolean isPause) throws ServiceException {
        ScheduleJob scheduleJob = select(jobId);
        scheduleJob.setPause(isPause);
        update(scheduleJob.getId(), scheduleJob);
        return scheduleJob;
    }
}

8. controller

@RestController
@RequestMapping("/job")
public class JobController {

    @Autowired
    private JobService jobService;

    @GetMapping
    public Object getAllJob() {
        return jobService.getAllJob();
    }

    @GetMapping("/{id}")
    public Object getJob(@PathVariable("id") Long jobId) throws ServiceException {
        return jobService.select(jobId);
    }

    @PutMapping("/update/{id}")
    public Object updateJob(@PathVariable("id") Long jobId, @RequestBody ScheduleJob newScheduleJob) throws ServiceException {
        return jobService.update(jobId, newScheduleJob);
    }

    @DeleteMapping("/delete/{id}")
    public Object deleteJob(@PathVariable("id") Long jobId) throws ServiceException {
        return jobService.delete(jobId);
    }

    @PostMapping("/save")
    public Object saveJob(@RequestBody ScheduleJob newScheduleJob) throws ServiceException {
        return jobService.add(newScheduleJob);
    }


    @GetMapping("/run/{id}")
    public Object runJob(@PathVariable("id") Long jobId) throws ServiceException {
        return jobService.run(jobId);
    }


    @GetMapping("/pause/{id}")
    public Object pauseJob(@PathVariable("id") Long jobId) throws ServiceException {
        return jobService.pause(jobId);
    }

    @GetMapping("/resume/{id}")
    public Object resumeJob(@PathVariable("id") Long jobId) throws ServiceException {
        return jobService.resume(jobId);
    }
}

上面提供了一套对ScheduleJob实体对应的增删改查

9. ScheduleUtil

封装了创建定时任务、更新任务、执行任务、暂停任务、继续执行任务、删除任务等对任务的各种操作

import com.example.quartz.exception.ServiceException;
import com.example.quartz.domain.ScheduleJob;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Created by mengday.zhang on 2018/4/5.
 */
public class ScheduleUtil {
    private final static Logger logger = LoggerFactory.getLogger(ScheduleUtil.class);

    /**
     * 获取 Trigger Key
     *
     * @param scheduleJob
     * @return
     */
    public static TriggerKey getTriggerKey(ScheduleJob scheduleJob) {
        return TriggerKey.triggerKey(scheduleJob.getTriggerName(), scheduleJob.getTriggerGroup());
    }

    /**
     * 获取 Job Key
     *
     * @param scheduleJob
     * @return
     */
    public static JobKey getJobKey(ScheduleJob scheduleJob) {
        return JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
    }

    /**
     * 获取 Cron Trigger
     *
     * @param scheduler
     * @param scheduleJob
     * @return
     * @throws ServiceException
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, ScheduleJob scheduleJob) throws ServiceException {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(scheduleJob));
        } catch (SchedulerException e) {
            throw new ServiceException("Get Cron trigger failed", e);
        }
    }

    /**
     * 创建任务
     *
     * @param scheduler
     * @param scheduleJob
     * @throws ServiceException
     */
    public static void createScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) throws ServiceException {
        try {
            // 要执行的 Job 的类
            Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(scheduleJob.getClassName()).newInstance().getClass();

            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                    .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                    .withDescription(scheduleJob.getDescription())
                    .build();

            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                    .withIdentity(scheduleJob.getTriggerName(), scheduleJob.getTriggerGroup())
                    .withDescription(scheduleJob.getDescription())
                    .withSchedule(scheduleBuilder)
                    .startNow()
                    .build();

            scheduler.scheduleJob(jobDetail, cronTrigger);

            logger.info("Create schedule job {}-{} success", scheduleJob.getJobGroup(), scheduleJob.getJobName());

            if (scheduleJob.isPause()) {
                pauseJob(scheduler, scheduleJob);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Execute schedule job failed");
            throw new ServiceException("Execute schedule job failed", e);
        }
    }

    /**
     * 更新任务
     *
     * @param scheduler
     * @param scheduleJob
     * @throws ServiceException
     */
    public static void updateScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) throws ServiceException {
        try {

            TriggerKey triggerKey = getTriggerKey(scheduleJob);

            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            CronTrigger cronTrigger = getCronTrigger(scheduler, scheduleJob);

            cronTrigger = cronTrigger.getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withDescription(scheduleJob.getDescription())
                    .withSchedule(cronScheduleBuilder).build();

            scheduler.rescheduleJob(triggerKey, cronTrigger);

            logger.info("Update schedule job {}-{} success", scheduleJob.getJobGroup(), scheduleJob.getJobName());

            if (scheduleJob.isPause()) {
                pauseJob(scheduler, scheduleJob);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
            logger.error("Update schedule job failed");
            throw new ServiceException("Update schedule job failed", e);
        }
    }

    /**
     * 执行任务
     *
     * @param scheduler
     * @param scheduleJob
     * @throws ServiceException
     */
    public static void run(Scheduler scheduler, ScheduleJob scheduleJob) throws ServiceException {
        try {
            scheduler.triggerJob(getJobKey(scheduleJob));
            logger.info("Run schedule job {}-{} success", scheduleJob.getJobGroup(), scheduleJob.getJobName());
        } catch (SchedulerException e) {
            e.printStackTrace();
            logger.error("Run schedule job failed");
            throw new ServiceException("Run schedule job failed", e);
        }
    }

    /**
     * 暂停任务
     *
     * @param scheduler
     * @param scheduleJob
     */
    public static void pauseJob(Scheduler scheduler, ScheduleJob scheduleJob) throws ServiceException {
        try {
            scheduler.pauseJob(getJobKey(scheduleJob));
            logger.info("Pause schedule job {}-{} success", scheduleJob.getJobGroup(), scheduleJob.getJobName());
        } catch (SchedulerException e) {
            e.printStackTrace();
            logger.error("Pause schedule job failed");
            throw new ServiceException("Pause job failed", e);
        }
    }

    /**
     * 继续执行任务
     *
     * @param scheduler
     * @param scheduleJob
     * @throws ServiceException
     */
    public static void resumeJob(Scheduler scheduler, ScheduleJob scheduleJob) throws ServiceException {
        try {
            scheduler.resumeJob(getJobKey(scheduleJob));
            logger.info("Resume schedule job {}-{} success", scheduleJob.getJobGroup(), scheduleJob.getJobName());
        } catch (SchedulerException e) {
            e.printStackTrace();
            logger.error("Resume schedule job failed");
            throw new ServiceException("Resume job failed", e);
        }
    }

    /**
     * 删除任务
     *
     * @param scheduler
     * @param scheduleJob
     * @throws ServiceException
     */
    public static void deleteJob(Scheduler scheduler, ScheduleJob scheduleJob) throws ServiceException {
        try {
            scheduler.deleteJob(getJobKey(scheduleJob));
            logger.info("Delete schedule job {}-{} success", scheduleJob.getJobGroup(), scheduleJob.getJobName());
        } catch (SchedulerException e) {
            e.printStackTrace();
            logger.error("Delete schedule job failed");
            throw new ServiceException("Delete job failed", e);
        }
    }
}

10. listener

import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class ApplicationListener implements CommandLineRunner {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private JobService jobService;

    @Autowired
    private Scheduler scheduler;

    @Override
    public void run(String... args) throws Exception {

        // 应用启动之后执行所有可执行的的任务
        List<ScheduleJob> scheduleJobList = jobService.getAllEnableJob();
        for (ScheduleJob scheduleJob : scheduleJobList) {
            try {
                CronTrigger cronTrigger = ScheduleUtil.getCronTrigger(scheduler, scheduleJob);
                if (cronTrigger == null) {
                    ScheduleUtil.createScheduleJob(scheduler, scheduleJob);
                } else {
                    ScheduleUtil.updateScheduleJob(scheduler, scheduleJob);
                }
                logger.info("Startup {}-{} success", scheduleJob.getJobGroup(), scheduleJob.getJobName());
            } catch (ServiceException e) {
                e.printStackTrace();
            }
        }
    }
}

11. job

Job 用于封装要定时执行的任务

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestJob implements Job {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        logger.info("Test job is executing...");
    }
}

12. 创建定时任务

这里使用Postman发送一个http请求到JobController#saveJob,可以看到每隔10秒就会执行TestJob下的execute方法。

这里写图片描述

{
    "className":"com.example.quartz.job.TestJob",
    "cronExpression":"*/10 * * * * ?",
    "jobName":"TestJob",
    "jobGroup":"TEST_GROUP",
    "triggerName":"TEST_TRIGGER",
    "triggerGroup":"TEST_GROUP",
    "pause": "false",
    "enable": "true",
    "description":"Test Job for SpringBoot"
}

这里写图片描述

这里写图片描述

其他操作

{
    "id":1,
    "className":"com.example.quartz.job.TestJob",
    "cronExpression":"*/5 * * * * ?",
    "jobName":"testJob",
    "jobGroup":"TEST_GROUP",
    "triggerName":"TEST_TRIGGER",
    "triggerGroup":"TEST_GROUP",
    "pause": "false",
    "enable": "true",
    "description":"test Job for SpringBoot"
}

对于定时任务的管理可以放在管理平台上,通过页面的形式来管理定时任务

相关文章:https://blog.csdn.net/u013360850/article/details/79318343

猜你喜欢

转载自blog.csdn.net/vbirdbest/article/details/79831666