quartz动态定时任务

场景:

需求:

支付的二维码,超过两个小时以后,如果还未支付,则自动转为取消支付,或者支付超时的状态

需求分析:

1,动态定时任务:

每个支付的二维码创建的时候,创建一个动态的定时任务,两个小时候自动执行,更新支付状态,可以解决这个问题。

(1)持久化:

如果服务重启了,动态定时任务会丢失,导致部分数据没办法更新状态。

(2)分布式:

如果当服务重启时,自动扫描数据,重新计算时间,再次创建动态定时任务。可以解决(1)的问题,但是当分布式,多个节点的时候,都会重新加载所有的任务,这样性能上不是最优解,只能在数据源上加上节点名称,不同的服务节点,加载属于自己的定时任务,可以解决这个问题。

虽然有那么多问题,还是封装一下,万一以后有用得到的时候呢

实现

1,创建Scheduler对象

2,基础对象,其中三个熟悉都是必须要用的,方便后期开发,仅需继承该类就可以了。

3,创建动态定时任务工具类。

4,测试

实现

创建bean

import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 创建scheduler对象
 *
 * @module
 * @author frank
 * @date 2021/8/21 11:51
 */
@Configuration
public class SchedulerConfig{
    /**
     * 初始注入scheduler
     *
     * @return
     * @throws SchedulerException
     */
    @Bean
    public Scheduler scheduler() throws SchedulerException {
        SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
        return schedulerFactoryBean.getScheduler();
    }
}

创建实体类父类

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.UUID;
/**
 * 创建动态定时任务基础父类
 * 
 * @module 
 * @author frank
 * @date 2021/8/21 11:51
 */
@Data
public class SchedulerBaseVo implements Serializable {

    /**
     * 任务名称-唯一
     */
    @ApiModelProperty(value = "任务名称")
    private String jobName;
    /**
     * 触发器名称-唯一
     */
    @ApiModelProperty(value = "触发器名称")
    private String triggerName;
    /**
     * 分组名称-唯一
     */
    @ApiModelProperty(value = "分组名称")
    private String groupName;

    public SchedulerBaseVo() {
        this.groupName = "notSchool";
        this.jobName = UUID.randomUUID().toString();
        this.triggerName = UUID.randomUUID().toString();
    }

    public SchedulerBaseVo(String jobName) {
        this.jobName = jobName;
        this.triggerName = jobName;
        this.groupName = "notSchool";
    }

    public SchedulerBaseVo(String jobName, String groupName) {
        this.jobName = jobName;
        this.triggerName = jobName;
        this.groupName = groupName;
    }

    public SchedulerBaseVo(String jobName, String triggerName, String groupName) {
        this.jobName = jobName;
        this.triggerName = triggerName;
        this.groupName = groupName;
    }

    public void init(String jobName,String groupName) {
        this.jobName = jobName;
        this.triggerName = jobName;
        this.groupName = groupName;
    }

}

创建动态定时任务工具类

import com.sxmaps.netschool.common.utils.DateUtil;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

/**
 * 创建动态定时任务
 *
 * @module
 * @author frank
 * @date 2021/8/21 11:50
 */
@Component
public class DynamicScheduledTask<T extends SchedulerBaseVo> {

    private final Logger logger = LoggerFactory.getLogger(DynamicScheduledTask.class);

    @Autowired
    Scheduler scheduler;

    /**
     * 创建并执行任务
     */
    private void createScheduler(T t, Date tsTime, String jobName, String triggerName, String groupName, int intervalInSeconds, Class<? extends Job> clazz) throws SchedulerException {
        logger.info("添加动态定时任务,任务名称:{},触发器名称:{},分组名称:{},触发间隔:{},执行时间:{},内容:{}" , jobName, triggerName,groupName,intervalInSeconds,tsTime,t);
        JobDetail job = JobBuilder.newJob(clazz).withIdentity(jobName, groupName).build();
        job.getJobDataMap().put(t.getClass().getName(), t);
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerName, groupName)
            .startAt(tsTime)
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(intervalInSeconds).withRepeatCount(0))
            .build();
        // 创建实例
        try {
            scheduler.scheduleJob(job, trigger);
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (SchedulerException e) {
            scheduler.shutdown(true);
            logger.error("创建动态定时任务失败:",e);
        }
    }
    /**
     * 创建并执行任务
     */
    public void createSchedulerHour(T t, Integer delay, Class<? extends Job> clazz)  {
        try {
            createScheduler(t, DateUtil.addHour(DateUtil.currentDate(),delay), t.getJobName(), t.getTriggerName(), t.getGroupName(), 10,clazz);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    /**
     * 创建并执行任务
     */
    public void createSchedulerSecond(T t, Integer delay, Class<? extends Job> clazz) {
        try {
            createScheduler(t, DateUtil.addSecond(DateUtil.currentDate(),delay), t.getJobName(), t.getTriggerName(), t.getGroupName(), 10,clazz);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    /**
     * 删除任务
     */
    public boolean deleteJob(String jobName, String groupName) {
        try {
            return scheduler.deleteJob(JobKey.jobKey(jobName, groupName));
        } catch (SchedulerException e) {
        }
        return Boolean.FALSE;
    }

    //--
    public void getAllJobs() throws SchedulerException {
        for (String groupName : scheduler.getJobGroupNames()) {
            for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                String jobName = jobKey.getName();
                String jobGroup = jobKey.getGroup();

                List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
                Date nextFireTime = triggers.get(0).getNextFireTime();
                logger.debug("========== jobName: {}, groupName: {}, nextTime: {}", jobName, jobGroup, nextFireTime);
            }
        }
    }
}

动态定时任务执行

import com.sxmaps.netschool.common.utils.SpringContextUtil;
import com.sxmaps.netschool.service.SchoolAccountService;
import com.sxmaps.netschool.service.dto.school.SchoolAccountPayStateRespDTO;
import com.sxmaps.netschool.service.vo.school.SchoolAccountPayStateReqVO;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 定时任务执行类
 *
 * @author frank
 * @module
 * @date 2021/8/19 10:49
 */
@Component
public class PayQCordJob implements Job {

    private final Logger logger = LoggerFactory.getLogger(PayQCordJob.class);


    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        SchoolAccountPayStateReqVO payStateReqVO = (SchoolAccountPayStateReqVO) context.getJobDetail().getJobDataMap().get(SchoolAccountPayStateReqVO.class.getName());
        logger.info("支付二维码-定时失效,内容:{}", payStateReqVO);
        SchoolAccountService schoolAccountService = (SchoolAccountService) SpringContextUtil.getBeanByClass(SchoolAccountService.class);
        SchoolAccountPayStateRespDTO respDTO = schoolAccountService.payState(payStateReqVO);
        logger.info("支付二维码-定时失效,内容:{},处理结果:{}", payStateReqVO, respDTO);
    }
}

测试

@Autowired
DynamicScheduledTask scheduledTask;
......
scheduledTask.createSchedulerSecond(new SchoolAccountPayStateReqVO(dto.getPayNo()),30, PayQCordJob.class);

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值