SpringBoot + quartz 实现简单的一次性定时任务

添加依赖


    org.springframework.boot
    spring-boot-starter-quartz
    2.3.11.RELEASE


创建调度器

import lombok.extern.slf4j.Slf4j;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

@Configuration
@Slf4j
@Order(99)
public class TaskConfig implements CommandLineRunner {

    public void init() {
        schedulerStart();
    }

    @Override
    public void run(String... args) {
        init();
    }

    public void schedulerStart() {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.start();
        } catch (SchedulerException e) {
            log.info("--- 启动Scheduler失败 ---", e);
        }
    }
}


 

 任务基类

import com.ganguomob.dev.base.infrastructure.exception.CommonBusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.triggers.SimpleTriggerImpl;

import java.time.Instant;
import java.util.Date;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * @author : Nash
 * @date : 2020-05-07 10:25
 */
@Slf4j
public abstract class BaseTask implements Job {

    /**
     * 填入任务类型(必填) eg: "order_pay_end:"
     */
    public abstract String getTypeName();

    /**
     * 任务名
     */
    public String getName() {
        return "taskName";
    }

    /**
     * 任务执行时间名
     */
    public String getTimeName() {
        return "timeAt";
    }

    /**
     * 到了任务执行时间会从这里出来
     * 如需接收其他的值,请修改BaseTask内的execute(JobExecutionContext context)方法
     */
    public abstract void nextStep(String value);

    public Class getMessageClass() {
        return this.getClass();
    }

    @Override
    public void execute(JobExecutionContext context) {
        JobDetail detail = context.getJobDetail();
        if (detail == null) {
            return;
        }
        String value = detail.getJobDataMap().getString(getName());
        if (Strings.isBlank(value)) {
            return;
        }
        nextStep(value);
    }

    /**
     * 加入任务(到时间一次执行无循环)
     *
     * @param value 任务参数
     * @param end   任务执行时间
     */
    public void time(String value, Instant end) {
        if (Strings.isBlank(value) || end == null) {
            throw new RuntimeException("参数不能为空");
        }

        try {
            //创建scheduler
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

            long second = end.toEpochMilli();

            TriggerKey triggerKey = new TriggerKey(getTypeName() + value);

            SimpleTriggerImpl trigger = (SimpleTriggerImpl) scheduler.getTrigger(triggerKey);
            JobDetail jobDetail = scheduler.getJobDetail(new JobKey(getTypeName() + value));
            if (trigger != null && jobDetail != null) {
                trigger.setStartTime(new Date(second));
                jobDetail = jobDetail.getJobBuilder()
                        .usingJobData(getName(), value)
                        .usingJobData(getTimeName(), second)
                        .build();

                // 删除任务调度
                scheduler.deleteJob(new JobKey(getTypeName() + value));
                //加入这个调度
                scheduler.scheduleJob(jobDetail, trigger);

            } else {
                //定义一个Trigger 设置开始和结束时间   类型+值拼接 eg: order_pay_end_orderId:1
                Trigger newTrigger = newTrigger().withIdentity(getTypeName() + value)
                        .startAt(new Date(second)
                        ).build();

                //定义一个JobDetail 传入携带参数 可用于查询执行时间
                //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
                JobDetail job = newJob(getMessageClass())
                        .withIdentity(getTypeName() + value)
                        .usingJobData(getName(), value)
                        .usingJobData(getTimeName(), second)
                        .build();

                //加入这个调度
                scheduler.scheduleJob(job, newTrigger);
            }
        } catch (Exception e) {
            log.info("--- 加入scheduler失败 ---", e);
        }
    }

    /**
     * 获取任务的执行时间
     */
    public Instant get(String value) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            JobDetail jobDetail = scheduler.getJobDetail(new JobKey(getTypeName() + value));
            if (jobDetail == null) {
                return null;
            }
            Long endAt = (Long) jobDetail.getJobDataMap().get(getTimeName());
            return Instant.ofEpochMilli(endAt);
        } catch (SchedulerException e) {
            log.info("--- 获取scheduler失败 ---", e);
            return null;
        }
    }

    /**
     * 判断任务调度是否存在
     */
    public Boolean isExist(String value) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            JobDetail jobDetail = scheduler.getJobDetail(new JobKey(getTypeName() + value));
            return jobDetail != null;
        } catch (SchedulerException e) {
            log.info("---  判断scheduler失败 ---", e);
            return false;
        }
    }

    /**
     * 删除任务调度
     */
    public void delete(String value) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            JobKey jobKey = new JobKey(getTypeName() + value);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail != null) {
                scheduler.deleteJob(jobKey);
            }
        } catch (SchedulerException e) {
            log.info("--- 删除scheduler失败 ---", e);
        }
    }
}

举一个例子

/**
 * @author : Nash
 * @date : 2020-05-08 15:02
 */
@Component
@Slf4j
public class CheckCouponEnd extends BaseTask {

    @Override
    public String getTypeName() {
        return "coupon_end:";
    }

    @Override
    public void nextStep(String value) {
        // 优惠劵到期
        AdminCouponService couponService = SpringContextUtil.getBean(AdminCouponService.class);
        couponService.addEndAt();
    }
}

注意:无法使用@Autowired注入Bean

 

@Autowired
private CheckCouponEnd mCheckCouponEnd;

public void checkCouponEnd(String id){
  // 传入优惠卷的id 和当前时间往后10s的时间戳 10s到了会从上面的nextStep方法中出来
  mCheckCouponEnd.time(id,Instant.now().plus(10,ChronoUnit.SECONDS));
}

 


直接继承BaseTask
实现getTypeName()方法,起一个名字
实现nextStep(String value)方法,定时任务的时间到了就会走这个方法

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