【转载】 《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); }