【转载】 《SpringBoot2.0 实战》系列-集成Quartz定时任务(持久化到数据库)

https://blog.csdn.net/HXNLYW/article/details/95055601

一、增加依赖

我们使用的spring-boot-starter-quartz,所以不用显示指定版本号

<!--quartz相关依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

 

二、yml配置信息

spring: 
  # 数据库配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      datasource:
        master:
          url: xxx
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: xxx
        quartz:
          url: xxx
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: xxx
  # quartz定时任务
  quartz:
    jdbc:
      # 初始化Quartz表结构,项目第一次启动配置程always,然后改成never 否则已生成的job会被初始化掉
      initialize-schema: never
    #设置quartz任务的数据持久化方式,默认是内存方式
    job-store-type: jdbc
    properties:
      org:
        quartz:
          scheduler:
            instanceName: etlCleanScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            tablePrefix: QRTZ_  #Quartz表前缀
            isClustered: true
            clusterCheckinInterval: 10000
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            #线程数 一个任务使用一个线程
            threadCount: 100
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true

自定生成表结构,需要配置如下信息:

spring.quartz.jdbc.initialize-schema: always
spring.quartz.job-store-type: jdbc

项目启动后生成的表信息

三、自定义数据源

其实到第二部配置就已经结束了,但是很多时候,我们希望quartz的数据源和项目的业务数据源是分离的,那我们需要再配置下数据源。

在启动类下增加以下代码:

/**
 * 主数据源
 * @return
 */
@Primary
@Bean
@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.master")
public DruidDataSource druidDataSource() {
    return new DruidDataSource();
}
 
 
/**
 * 配置Quartz独立数据源的配置
 */
@Bean
@QuartzDataSource
@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.quartz")
public DataSource quartzDataSource(){
    return new DruidDataSource();
}

注意

一定要增加主数据源,并加上@primary注解,不然业务用的数据源会切换到quartz数据源

四、定时任务逻辑封装

QuartzService定时器操作业务类,需要增加数据源切换注解。

/**
 * quartz逻辑
 * @author gourd
 */
@Service
@DS("quartz")
public class QuartzServiceImpl implements QuartzService {
 
    @Autowired
    private Scheduler scheduler;
 
    @PostConstruct
    public void startScheduler() {
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 增加一个job
     * 
     * @param jobClass
     *            任务实现类
     * @param jobName
     *            任务名称
     * @param jobGroupName
     *            任务组名
     * @param jobTime
     *            时间表达式 (这是每隔多少秒为一次任务)
     * @param jobTimes
     *            运行的次数 (<0:表示不限次数)
     * @param jobData
     *            参数
     */
    @Override
    public void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, int jobTime,
                       int jobTimes, Map jobData) {
        try {
            // 任务名称和组构成任务key
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)
                    .build();
            // 设置job参数
            if(jobData!= null && jobData.size()>0){
                jobDetail.getJobDataMap().putAll(jobData);
            }
            // 使用simpleTrigger规则
            Trigger trigger = null;
            if (jobTimes < 0) {
                trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
                        .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime))
                        .startNow().build();
            } else {
                trigger = TriggerBuilder
                        .newTrigger().withIdentity(jobName, jobGroupName).withSchedule(SimpleScheduleBuilder
                                .repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes))
                        .startNow().build();
            }
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 增加一个job
     * 
     * @param jobClass
     *            任务实现类
     * @param jobName
     *            任务名称(建议唯一)
     * @param jobGroupName
     *            任务组名
     * @param jobTime
     *            时间表达式 (如:0/5 * * * * ? )
     * @param jobData
     *            参数
     */
    @Override
    public void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, String jobTime, Map jobData) {
        try {
            // 创建jobDetail实例,绑定Job实现类
            // 指明job的名称,所在组的名称,以及绑定job类
            // 任务名称和组构成任务key
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)
                    .build();
            // 设置job参数
            if(jobData!= null && jobData.size()>0){
                jobDetail.getJobDataMap().putAll(jobData);
            }
            // 定义调度触发规则
            // 使用cornTrigger规则
            // 触发器key
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
                    .startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
                    .withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).startNow().build();
            // 把作业和触发器注册到任务调度中
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 修改 一个job的 时间表达式
     * 
     * @param jobName
     * @param jobGroupName
     * @param jobTime
     */
    @Override
    public void updateJob(String jobName, String jobGroupName, String jobTime) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();
            // 重启触发器
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 删除任务一个job
     * 
     * @param jobName
     *            任务名称
     * @param jobGroupName
     *            任务组名
     */
    @Override
    public void deleteJob(String jobName, String jobGroupName) {
        try {
            scheduler.deleteJob(new JobKey(jobName, jobGroupName));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 暂停一个job
     * 
     * @param jobName
     * @param jobGroupName
     */
    @Override
    public void pauseJob(String jobName, String jobGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 恢复一个job
     * 
     * @param jobName
     * @param jobGroupName
     */
    @Override
    public void resumeJob(String jobName, String jobGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 立即执行一个job
     * 
     * @param jobName
     * @param jobGroupName
     */
    @Override
    public void runAJobNow(String jobName, String jobGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 获取所有计划中的任务列表
     * 
     * @return
     */
    @Override
    public List<Map<String, Object>> queryAllJob() {
        List<Map<String, Object>> jobList = null;
        try {
            GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            jobList = new ArrayList<Map<String, Object>>();
            for (JobKey jobKey : jobKeys) {
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("jobName", jobKey.getName());
                    map.put("jobGroupName", jobKey.getGroup());
                    map.put("description", "触发器:" + trigger.getKey());
                    Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                    map.put("jobStatus", triggerState.name());
                    if (trigger instanceof CronTrigger) {
                        CronTrigger cronTrigger = (CronTrigger) trigger;
                        String cronExpression = cronTrigger.getCronExpression();
                        map.put("jobTime", cronExpression);
                    }
                    jobList.add(map);
                }
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return jobList;
    }
 
    /**
     * 获取所有正在运行的job
     * 
     * @return
     */
    @Override
    public List<Map<String, Object>> queryRunJob() {
        List<Map<String, Object>> jobList = null;
        try {
            List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
            jobList = new ArrayList<Map<String, Object>>(executingJobs.size());
            for (JobExecutionContext executingJob : executingJobs) {
                Map<String, Object> map = new HashMap<String, Object>();
                JobDetail jobDetail = executingJob.getJobDetail();
                JobKey jobKey = jobDetail.getKey();
                Trigger trigger = executingJob.getTrigger();
                map.put("jobName", jobKey.getName());
                map.put("jobGroupName", jobKey.getGroup());
                map.put("description", "触发器:" + trigger.getKey());
                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                map.put("jobStatus", triggerState.name());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    map.put("jobTime", cronExpression);
                }
                jobList.add(map);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return jobList;
    }
 
}

具体的Job类

import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
 
import java.util.Date;
 
/**
 * job触发时间
 * @author gourd
 */
@Component
public class Job extends QuartzJobBean {
 
    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println(new Date() + "    job执行");
        // 获取参数
        JobDataMap jobDataMap = arg0.getJobDetail().getJobDataMap();
        // 业务逻辑 ...
    }
 
}

cron工具类,将date 转换成cron格式

import java.text.SimpleDateFormat;
import java.util.Date;
 
public class QuartzCronDateUtils {
    /*** 
     *  日期转换cron表达式时间格式
     * @param date 
     * @param dateFormat
     * @return 
     */  
    public static String formatDateByPattern(Date date,String dateFormat){  
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);  
        String formatTimeStr = null;  
        if (date != null) {  
            formatTimeStr = sdf.format(date);  
        }  
        return formatTimeStr;  
    }  
    /*** 
     * convert Date to cron 
     * @param date:时间
     * @return 
     */  
    public static String getCron(Date  date){
        String dateFormat="ss mm HH dd MM ? yyyy";  
        return formatDateByPattern(date,dateFormat);  
    }  
}

五、测试

@Autowired
private QuartzService quartzService;
 
@PostMapping("/addjob")
@ApiOperation(value = "增加定时任务")
public void addJob() {
    Map map = new HashMap(2);
    map.put("id",1L);
    quartzService.addJob(Job.class, "job", "test", "0/30 * * * * ?",map);
}
原文地址:https://www.cnblogs.com/exmyth/p/14296817.html