springboot+quartz实现动态任务调度

1.maven pom引入依赖

                
        
            org.quartz-scheduler
            quartz
            2.2.3
        
        
            org.quartz-scheduler
            quartz-jobs
            2.2.3
        
        
            org.springframework
            spring-context-support
        

2.数据库建立quartz相关表

执行quartz建表sql即可。

3.quartz配置文件quartz.properties

# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#

org.quartz.scheduler.instanceName: DefaultQuartzScheduler

#如果使用集群,instanceId必须唯一,设置成AUTO
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 50
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000


#============================================================================
# Configure JobStore
#============================================================================
#
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#存储方式使用JobStoreTX,也就是数据库
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties:false
#数据库中quartz表的表名前缀
org.quartz.jobStore.tablePrefix:QRTZ_
org.quartz.jobStore.dataSource:qzDS
#是否使用集群(如果项目只部署到 一台服务器,就不用了)
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 30000

#============================================================================
# Configure Datasources
#============================================================================
#配置数据源
org.quartz.dataSource.qzDS.driver:com.mysql.cj.jdbc.Driver
org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/micro_mall?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
org.quartz.dataSource.qzDS.user:root
org.quartz.dataSource.qzDS.password:`1qazx
org.quartz.dataSource.qzDS.validationQuery=select 0 from dual

此处需说明:org.quartz.jobStore.userProperties值为true时,标记指示着持久性 JobStore 所有在 JobDataMap 中的值都是字符串,因此能以 名-值 对的形式存储,而不用让更复杂的对象以序列化的形式存入 BLOB 列中。

job工厂:

 
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
 
@Component
public class SpringJobFactory extends AdaptableJobFactory {
 
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;
 
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

定时任务配置:

package com.hxkg.datafusion.schedule;
 
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
 
import java.io.IOException;
import java.util.Properties;
 
/**
 * 定时任务配置
 *
 * @author yangfeng
 * @date 2018-07-03
 */
@Configuration
public class QuartzConfig {
    @Autowired
    private SpringJobFactory springJobFactory;
 
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        //获取配置属性
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
        //在quartz.properties中的属性被读取并注入后再初始化对象
        propertiesFactoryBean.afterPropertiesSet();
        //创建SchedulerFactoryBean
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        Properties pro = propertiesFactoryBean.getObject();
        factory.setOverwriteExistingJobs(true);
        factory.setAutoStartup(true);
        factory.setQuartzProperties(pro);
        factory.setJobFactory(springJobFactory);
        return factory;
    }
 
    @Bean
    public Scheduler scheduler() throws IOException{
        return schedulerFactoryBean().getScheduler();
    }
}

4.任务调度表结构

CREATE TABLE `schedule_job` (
  `id` varchar(32) NOT NULL,
  `job_name` varchar(126) NOT NULL COMMENT '任务名称',
  `bean_name` varchar(126) NOT NULL COMMENT 'bean名称',
  `cron_expression` varchar(126) NOT NULL COMMENT '表达式',
  `method_name` varchar(32) DEFAULT NULL COMMENT '方法名',
  `params` varchar(32) DEFAULT NULL COMMENT '参数',
  `status` int(1) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `createBy` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='任务调度表';

5.任务调度实体

package com.mall.shop.entity.gen;

import java.io.Serializable;
import java.util.Date;

public class ScheduleJob implements Serializable {
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.id
     *
     * @mbggenerated
     */
    private String id;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.job_name
     *
     * @mbggenerated
     */
    private String jobName;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.bean_name
     *
     * @mbggenerated
     */
    private String beanName;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.cron_expression
     *
     * @mbggenerated
     */
    private String cronExpression;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.method_name
     *
     * @mbggenerated
     */
    private String methodName;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.params
     *
     * @mbggenerated
     */
    private String params;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.status
     *
     * @mbggenerated
     */
    private Integer status;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.create_time
     *
     * @mbggenerated
     */
    private Date createTime;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column schedule_job.createBy
     *
     * @mbggenerated
     */
    private String createby;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database table schedule_job
     *
     * @mbggenerated
     */
    private static final long serialVersionUID = 1L;

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.id
     *
     * @return the value of schedule_job.id
     *
     * @mbggenerated
     */
    public String getId() {
        return id;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.id
     *
     * @param id the value for schedule_job.id
     *
     * @mbggenerated
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.job_name
     *
     * @return the value of schedule_job.job_name
     *
     * @mbggenerated
     */
    public String getJobName() {
        return jobName;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.job_name
     *
     * @param jobName the value for schedule_job.job_name
     *
     * @mbggenerated
     */
    public void setJobName(String jobName) {
        this.jobName = jobName == null ? null : jobName.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.bean_name
     *
     * @return the value of schedule_job.bean_name
     *
     * @mbggenerated
     */
    public String getBeanName() {
        return beanName;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.bean_name
     *
     * @param beanName the value for schedule_job.bean_name
     *
     * @mbggenerated
     */
    public void setBeanName(String beanName) {
        this.beanName = beanName == null ? null : beanName.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.cron_expression
     *
     * @return the value of schedule_job.cron_expression
     *
     * @mbggenerated
     */
    public String getCronExpression() {
        return cronExpression;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.cron_expression
     *
     * @param cronExpression the value for schedule_job.cron_expression
     *
     * @mbggenerated
     */
    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression == null ? null : cronExpression.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.method_name
     *
     * @return the value of schedule_job.method_name
     *
     * @mbggenerated
     */
    public String getMethodName() {
        return methodName;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.method_name
     *
     * @param methodName the value for schedule_job.method_name
     *
     * @mbggenerated
     */
    public void setMethodName(String methodName) {
        this.methodName = methodName == null ? null : methodName.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.params
     *
     * @return the value of schedule_job.params
     *
     * @mbggenerated
     */
    public String getParams() {
        return params;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.params
     *
     * @param params the value for schedule_job.params
     *
     * @mbggenerated
     */
    public void setParams(String params) {
        this.params = params == null ? null : params.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.status
     *
     * @return the value of schedule_job.status
     *
     * @mbggenerated
     */
    public Integer getStatus() {
        return status;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.status
     *
     * @param status the value for schedule_job.status
     *
     * @mbggenerated
     */
    public void setStatus(Integer status) {
        this.status = status;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.create_time
     *
     * @return the value of schedule_job.create_time
     *
     * @mbggenerated
     */
    public Date getCreateTime() {
        return createTime;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.create_time
     *
     * @param createTime the value for schedule_job.create_time
     *
     * @mbggenerated
     */
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column schedule_job.createBy
     *
     * @return the value of schedule_job.createBy
     *
     * @mbggenerated
     */
    public String getCreateby() {
        return createby;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column schedule_job.createBy
     *
     * @param createby the value for schedule_job.createBy
     *
     * @mbggenerated
     */
    public void setCreateby(String createby) {
        this.createby = createby == null ? null : createby.trim();
    }
}

实体扩展类:

package com.mall.shop.entity.customized;

import java.io.Serializable;
import com.mall.shop.entity.gen.ScheduleJob;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;

/**
 * 应用对象 - ScheduleJob.
 * 

* 该类于 2021-05-21 13:56:38 首次生成,后由开发手工维护。 *

* @author yangfeng * @version 1.0.0, May 21, 2021 */ @JsonSerialize(include = Inclusion.ALWAYS) public final class ScheduleJobAO extends ScheduleJob implements Serializable { /** * 默认的序列化 id. */ private static final long serialVersionUID = 1L; @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); } }

6.接口服务

package com.mall.shop.service;

import com.backstage.core.result.ServiceResult;
import com.backstage.core.service.IBaseAOService;
import com.mall.shop.dto.request.ScheduleJobRequest;
import com.mall.shop.entity.customized.ScheduleJobAO;
import com.mall.shop.entity.gen.ScheduleJobCriteria;

import java.util.List;

public interface IScheduleJobService extends IBaseAOService {

    ServiceResult> list(ScheduleJobRequest request);

    ServiceResult> listByCondition(ScheduleJobRequest request);

    ServiceResult add(ScheduleJobAO scheduleJob);

    ServiceResult update(ScheduleJobAO scheduleJob);

    ServiceResult deleteBatch(String[] jobIds);

    ServiceResult run(String[] jobIds);

    ServiceResult pause(String[] jobIds);

    ServiceResult resume(String[] jobIds);
}
package com.mall.shop.service.impl;

import com.backstage.common.page.Page;
import com.backstage.core.mapper.BaseGeneratedMapper;
import com.backstage.core.result.ServiceResult;
import com.backstage.core.result.ServiceResultHelper;
import com.backstage.core.service.AbstractBaseAOService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mall.shop.dao.customized.ScheduleJobCustomizedMapper;
import com.mall.shop.dao.gen.ScheduleJobGeneratedMapper;
import com.mall.shop.dto.request.ScheduleJobRequest;
import com.mall.shop.entity.customized.ScheduleJobAO;
import com.mall.shop.entity.gen.ScheduleJob;
import com.mall.shop.entity.gen.ScheduleJobCriteria;
import com.mall.shop.enums.ScheduleStatus;
import com.mall.shop.service.IScheduleJobService;
import com.mall.shop.util.ScheduleUtils;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 任务调度服务
 *
 * @author yangfeng
 */
@Service
public class ScheduleJobService extends AbstractBaseAOService implements IScheduleJobService {

    @Resource
    private ScheduleJobGeneratedMapper scheduleJobGeneratedMapper;

    @Resource
    private ScheduleJobCustomizedMapper scheduleJobCustomizedMapper;

    @Override
    protected BaseGeneratedMapper getGeneratedMapper() {
        return scheduleJobGeneratedMapper;
    }

    @Autowired
    private Scheduler scheduler;

    /**
     * 项目启动时,初始化定时器
     */
    @PostConstruct
    public void init() {
        List scheduleJobList = this.listByCondition(null).getData();
        for (ScheduleJobAO scheduleJob : scheduleJobList) {
            CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getId());
            //如果不存在,则创建
            if (cronTrigger == null) {
                ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
            } else {
                ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
            }
        }
    }


    /**
     * 分页查询
     *
     * @param request
     * @return
     */
    @Override
    public ServiceResult> list(ScheduleJobRequest request) {
        ServiceResult> ret = new ServiceResult();
        PageHelper.startPage(request.getPageNo(), request.getPageSize());
        List scheduleJobAOList = scheduleJobCustomizedMapper.listByCondition(request);
        ret.setData(scheduleJobAOList);
        ret.setSucceed(true);
        ret.setAdditionalProperties("page", Page.obtainPage(new PageInfo(scheduleJobAOList)));
        return ret;
    }

    @Override
    public ServiceResult> listByCondition(ScheduleJobRequest request) {
        return ServiceResultHelper.genResultWithSuccess(scheduleJobCustomizedMapper.listByCondition(request));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult add(ScheduleJobAO scheduleJob) {
        scheduleJob.setCreateTime(new Date());
        scheduleJob.setStatus(ScheduleStatus.NORMAL.getValue());
        this.insert(scheduleJob);

        ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
        return ServiceResultHelper.genResultWithSuccess();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult update(ScheduleJobAO scheduleJob) {
        ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
        this.saveOrUpdate(scheduleJob);
        return ServiceResultHelper.genResultWithSuccess();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult deleteBatch(String[] jobIds) {
        for (String jobId : jobIds) {
            ScheduleUtils.deleteScheduleJob(scheduler, jobId);
            deleteById(jobId);
        }
        return ServiceResultHelper.genResultWithSuccess();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult run(String[] jobIds) {
        for (String jobId : jobIds) {
            ScheduleUtils.run(scheduler, selectByPrimaryKey(jobId).getData());
        }
        return ServiceResultHelper.genResultWithSuccess();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult pause(String[] jobIds) {
        for (String jobId : jobIds) {
            ScheduleUtils.pauseJob(scheduler, jobId);
        }

        return updateBatch(jobIds, ScheduleStatus.PAUSE.getValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult resume(String[] jobIds) {
        for (String jobId : jobIds) {
            ScheduleUtils.resumeJob(scheduler, jobId);
        }

        return updateBatch(jobIds, ScheduleStatus.NORMAL.getValue());
    }

    public ServiceResult updateBatch(String[] jobIds, int status) {
        for (String jobId : jobIds) {
            ScheduleJobAO scheduleJob = new ScheduleJobAO();
            scheduleJob.setId(jobId);
            scheduleJob.setStatus(status);
            this.saveOrUpdate(scheduleJob);
        }
        return ServiceResultHelper.genResultWithSuccess();
    }

}

7.动态调度相关
ScheduleUtils工具类:
package com.mall.shop.util;

import com.backstage.common.exception.BaseException;
import com.mall.shop.entity.customized.ScheduleJobAO;
import com.mall.shop.entity.gen.ScheduleJob;
import com.mall.shop.enums.ScheduleStatus;
import org.quartz.*;

/**
 * 定时任务工具类
 *
 */
public class ScheduleUtils {
    private final static String JOB_NAME = "TASK_";

    /**
     * 任务调度参数key
     */
    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";

    /**
     * 获取触发器key
     */
    public static TriggerKey getTriggerKey(String jobId) {
        return TriggerKey.triggerKey(JOB_NAME + jobId);
    }

    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(String jobId) {
        return JobKey.jobKey(JOB_NAME + jobId);
    }

    /**
     * 获取表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
        } catch (SchedulerException e) {
            throw new BaseException(-1, "获取定时任务CronTrigger出现异常" + e.getMessage());
        }
    }

    /**
     * 创建定时任务
     */
    public static void createScheduleJob(Scheduler scheduler, ScheduleJobAO scheduleJob) {
        try {
            //构建job信息
            JobDetail jobDetail = JobBuilder.newJob(ScheduleJobExec.class).withIdentity(getJobKey(scheduleJob.getId())).build();

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getId())).withSchedule(scheduleBuilder).build();

            //放入参数,运行时的方法可以获取
            jobDetail.getJobDataMap().put(JOB_PARAM_KEY, scheduleJob);

            scheduler.scheduleJob(jobDetail, trigger);

            //暂停任务
            if (scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()) {
                pauseJob(scheduler, scheduleJob.getId());
            }
        } catch (SchedulerException e) {
            throw new BaseException(-1, "创建定时任务失败" + e.getMessage());
        }
    }

    /**
     * 更新定时任务
     */
    public static void updateScheduleJob(Scheduler scheduler, ScheduleJobAO scheduleJob) {
        try {
            TriggerKey triggerKey = getTriggerKey(scheduleJob.getId());

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getId());

            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            //参数
            trigger.getJobDataMap().put(JOB_PARAM_KEY, scheduleJob);

            scheduler.rescheduleJob(triggerKey, trigger);

            //暂停任务
            if (scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()) {
                pauseJob(scheduler, scheduleJob.getId());
            }

        } catch (SchedulerException e) {
            throw new BaseException(-1, "更新定时任务失败" + e.getMessage());
        }
    }

    /**
     * 立即执行任务
     */
    public static void run(Scheduler scheduler, ScheduleJobAO scheduleJob) {
        try {
            //参数
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(JOB_PARAM_KEY, scheduleJob);

            scheduler.triggerJob(getJobKey(scheduleJob.getId()), dataMap);
        } catch (SchedulerException e) {
            throw new BaseException(-1, "立即执行定时任务失败" + e.getMessage());
        }
    }

    /**
     * 暂停任务
     */
    public static void pauseJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.pauseJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new BaseException(-1, "暂停定时任务失败" + e.getMessage());
        }
    }

    /**
     * 恢复任务
     */
    public static void resumeJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.resumeJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new BaseException(-1, "恢复定时任务失败" + e.getMessage());
        }
    }

    /**
     * 删除定时任务
     */
    public static void deleteScheduleJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.deleteJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new BaseException(-1, "删除定时任务失败" + e.getMessage());
        }
    }
}

定时任务调度类ScheduleJobExec:

package com.mall.shop.util;

import com.alibaba.fastjson.JSON;
import com.mall.shop.entity.customized.ScheduleJobAO;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


/**
 * 定时任务
 */
public class ScheduleJobExec extends QuartzJobBean {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private ExecutorService service = Executors.newSingleThreadExecutor();

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        Object o = context.getMergedJobDataMap().get(ScheduleUtils.JOB_PARAM_KEY);
        ScheduleJobAO scheduleJob;
        if (o instanceof ScheduleJobAO) {
            scheduleJob = (ScheduleJobAO) o;
        } else {
            scheduleJob = JSON.parseObject(JSON.toJSON(o).toString(), ScheduleJobAO.class);
        }
        //任务开始时间
        long startTime = System.currentTimeMillis();

        try {
            //执行任务
            logger.info("任务准备执行,任务ID:" + scheduleJob.getId());
            ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(),
                    scheduleJob.getMethodName(), scheduleJob.getParams());
            Future future = service.submit(task);

            future.get();

            //任务执行总时长
            long times = System.currentTimeMillis() - startTime;

            logger.info("任务执行完毕,任务ID:" + scheduleJob.getId() + "  总共耗时:" + times + "毫秒");
        } catch (Exception e) {
            logger.error("任务执行失败,任务ID:" + scheduleJob.getId(), e);
        } finally {
        }
    }
}

反射执行定时任务线程类:

package com.mall.shop.util;

import com.backstage.common.exception.BaseException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

/**
 * 执行定时任务
 *
 */
public class ScheduleRunnable implements Runnable {
    private Object target;
    private Method method;
    private String params;

    public ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException {
        this.target = SpringContextUtils.getBean(beanName);
        this.params = params;

        if (StringUtils.isNotBlank(params)) {
            this.method = target.getClass().getDeclaredMethod(methodName, String.class);
        } else {
            this.method = target.getClass().getDeclaredMethod(methodName);
        }
    }

    @Override
    public void run() {
        try {
            ReflectionUtils.makeAccessible(method);
            if (StringUtils.isNotBlank(params)) {
                method.invoke(target, params);
            } else {
                method.invoke(target);
            }
        } catch (Exception e) {
            throw new BaseException(-1, "执行定时任务失败" + e.getMessage());
        }
    }

}
Spring Context 工具类:
package com.mall.shop.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Spring Context 工具类
 *
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {
    public static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }

    public static  T getBean(String name, Class requiredType) {
        return applicationContext.getBean(name, requiredType);
    }

    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    public static boolean isSingleton(String name) {
        return applicationContext.isSingleton(name);
    }

    public static Class getType(String name) {
        return applicationContext.getType(name);
    }

    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public static  T getBean(Class requiredType) {
        return applicationContext.getBean(requiredType);
    }
}

8.controller

package com.mall.shop.controller;


import com.backstage.system.log.LogOperation;
import com.mall.shop.dto.request.ScheduleJobRequest;
import com.mall.shop.entity.customized.ScheduleJobAO;
import com.mall.shop.service.IScheduleJobService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * Created by yangfeng on 2020/01/23.
 * 任务调度 controller
 */
@RestController
public class ScheduleJobController {

    private static Logger LOG = LoggerFactory.getLogger(ScheduleJobController.class);

    @Resource
    private IScheduleJobService scheduleJobService;

    /**
     * 分页查询任务调度
     *
     * @return
     */
    @PostMapping(value = "/scheduleJob/list")
    @RequiresPermissions(value = {"scheduleJob:view", "scheduleJob:manage"}, logical = Logical.OR)
    @LogOperation(action = "分页查询任务调度")
    public Object list(ScheduleJobRequest request) {
        return scheduleJobService.list(request);
    }

    /**
     * 新增任务调度
     *
     * @param scheduleJob
     * @return
     */
    @PostMapping(value = "/scheduleJob/add")
    @RequiresPermissions("scheduleJob:manage")
    @LogOperation(action = "新增任务调度")
    public Object add(ScheduleJobAO scheduleJob) {
        return scheduleJobService.add(scheduleJob);
    }

    /**
     * 修改任务调度
     *
     * @param scheduleJob
     * @return
     */
    @PostMapping(value = "/scheduleJob/update")
    @RequiresPermissions("scheduleJob:manage")
    @LogOperation(action = "修改任务调度")
    public Object update(ScheduleJobAO scheduleJob) {
        return scheduleJobService.update(scheduleJob);
    }

    /**
     * 删除任务调度
     *
     * @return
     */
    @PostMapping(value = "/scheduleJob/delete")
    @RequiresPermissions("scheduleJob:manage")
    @LogOperation(action = "删除任务调度")
    public Object delete(String[] jobIds) {
        return scheduleJobService.deleteBatch(jobIds);
    }


    @LogOperation(action = "立即执行任务")
    @PostMapping("/scheduleJob/run")
    @RequiresPermissions("scheduleJob:manage")
    public Object run(String[] jobIds) {
        return scheduleJobService.run(jobIds);
    }

    /**
     * 暂停定时任务
     *
     * @param jobIds jobIds
     */
    @LogOperation(action = "暂停定时任务")
    @PostMapping("/scheduleJob/pause")
    @RequiresPermissions("scheduleJob:manage")
    public Object pause(String[] jobIds) {
        return scheduleJobService.pause(jobIds);
    }

    /**
     * 恢复定时任务
     *
     * @param jobIds jobIds
     */
    @LogOperation(action = "恢复定时任务")
    @PostMapping("/scheduleJob/resume")
    @RequiresPermissions("scheduleJob:manage")
    public Object resume(String[] jobIds) {
        return scheduleJobService.resume(jobIds);
    }

}

9.前端页面

springboot+quartz实现动态任务调度_第1张图片
10.任务执行类:

package com.mall.shop.schedule;

import com.mall.shop.entity.customized.PurchaseOrderAO;
import com.mall.shop.enums.OrderStatus;
import com.mall.shop.service.IPurchaseOrderService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * 过期自动取消订单
 */
@Component
public class OrderTask {

    @Resource
    private IPurchaseOrderService purchaseOrderService;

    public void expireOrder() {
        List orderList = purchaseOrderService.listExpireOrder().getData();
        if (!CollectionUtils.isEmpty(orderList)) {
            orderList.stream().forEach(o -> {
                o.setOrderStatus(OrderStatus.YQX.getCode());
                purchaseOrderService.update(o);
            });
        }
    }
}

 

你可能感兴趣的:(quartz)