SpringBoot2整合QuartJob如何实现定时器实时管理功能
创始人
2024-12-23 20:41:20
0次

一、QuartJob简介

1、一句话描述

Quartz是一个完全由java编写的开源作业调度框架,形式简易,功能强大。

2、核心API

(1)、Scheduler

代表一个 Quartz 的独立运行容器,Scheduler 将 Trigger 绑定到特定 JobDetail, 这样当 Trigger 触发时, 对应的 Job 就会被调度。

(2)、Trigger

描述 Job 执行的时间触发规则。主要有 SimpleTrigger 和 CronTrigger 两个子类,通过一个 TriggerKey 唯一标识。

(3)、Job

定义一个任务,规定了任务是执行时的行为。JobExecutionContext 提供了调度器的上下文信息,Job 的数据可从 JobDataMap 中获取。

(4)、JobDetail

Quartz 在每次执行 Job 时,都重新创建一个 Job 实例,所以它不直接接受一个 Job 的实例,相反它接收一个 Job 实现类。描述 Job 的实现类及其它相关的静态信息,如 Job 名字、描述等。

二、与SpringBoot2.0 整合

1、项目结构

版本描述

spring-boot:2.1.3.RELEASEquart-job:2.3.0

2、定时器配置

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.quartz.SchedulerFactoryBean;import javax.sql.DataSource;import java.util.Properties;@Configurationpublic class ScheduleConfig { @Bean public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) { // Quartz参数配置 Properties prop = new Properties(); // Schedule调度器的实体名字 prop.put("org.quartz.scheduler.instanceName", "HuskyScheduler"); // 设置为AUTO时使用,默认的实现org.quartz.scheduler.SimpleInstanceGenerator是基于主机名称和时间戳生成。 prop.put("org.quartz.scheduler.instanceId", "AUTO"); // 线程池配置 prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); prop.put("org.quartz.threadPool.threadCount", "20"); prop.put("org.quartz.threadPool.threadPriority", "5"); // JobStore配置:Scheduler在运行时用来存储相关的信息 // JDBCJobStore和JobStoreTX都使用关系数据库来存储Schedule相关的信息。 // JobStoreTX在每次执行任务后都使用commit或者rollback来提交更改。 prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); // 集群配置:如果有多个调度器实体的话则必须设置为true prop.put("org.quartz.jobStore.isClustered", "true"); // 集群配置:检查集群下的其他调度器实体的时间间隔 prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); // 设置一个频度(毫秒),用于实例报告给集群中的其他实例 prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); // 触发器触发失败后再次触犯的时间间隔 prop.put("org.quartz.jobStore.misfireThreshold", "12000"); // 数据库表前缀 prop.put("org.quartz.jobStore.tablePrefix", "qrtz_"); // 从 LOCKS 表查询一行并对这行记录加锁的 SQL 语句 prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); // 定时器工厂配置 SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setDataSource(dataSource); factory.setQuartzProperties(prop); factory.setSchedulerName("HuskyScheduler"); factory.setStartupDelay(30); factory.setApplicationContextSchedulerContextKey("applicationContextKey"); // 可选,QuartzScheduler 启动时更新己存在的Job factory.setOverwriteExistingJobs(true); // 设置自动启动,默认为true factory.setAutoStartup(true); return factory; }}

3、定时器管理工具

import com.quart.job.entity.ScheduleJobBean;import org.quartz.*;/** * 定时器工具类 */public class ScheduleUtil { private ScheduleUtil (){} private static final String SCHEDULE_NAME = "HUSKY_" ; /** * 触发器 KEY */ public static TriggerKey getTriggerKey(Long jobId){ return TriggerKey.triggerKey(SCHEDULE_NAME+jobId) ; } /** * 定时器 Key */ public static JobKey getJobKey (Long jobId){ return JobKey.jobKey(SCHEDULE_NAME+jobId) ; } /** * 表达式触发器 */ public static CronTrigger getCronTrigger (Scheduler scheduler,Long jobId){ try {  return (CronTrigger)scheduler.getTrigger(getTriggerKey(jobId)) ; } catch (SchedulerException e){  throw new RuntimeException("getCronTrigger Fail",e) ; } } /** * 创建定时器 */ public static void createJob (Scheduler scheduler, ScheduleJobBean scheduleJob){ try {  // 构建定时器  JobDetail jobDetail = JobBuilder.newJob(TaskJobLog.class).withIdentity(getJobKey(scheduleJob.getJobId())).build() ;  CronScheduleBuilder scheduleBuilder = CronScheduleBuilder   .cronSchedule(scheduleJob.getCronExpression())   .withMisfireHandlingInstructionDoNothing() ;  CronTrigger trigger = TriggerBuilder.newTrigger()   .withIdentity(getTriggerKey(scheduleJob.getJobId()))   .withSchedule(scheduleBuilder).build() ;  jobDetail.getJobDataMap().put(ScheduleJobBean.JOB_PARAM_KEY,scheduleJob);  scheduler.scheduleJob(jobDetail,trigger) ;  // 如果该定时器处于暂停状态  if (scheduleJob.getStatus() == 1){  pauseJob(scheduler,scheduleJob.getJobId()) ;  } } catch (SchedulerException e){  throw new RuntimeException("createJob Fail",e) ; } } /** * 更新定时任务 */ public static void updateJob(Scheduler scheduler, ScheduleJobBean scheduleJob) { try {  // 构建定时器  TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId());  CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())   .withMisfireHandlingInstructionDoNothing();  CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId());  trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();  trigger.getJobDataMap().put(ScheduleJobBean.JOB_PARAM_KEY, scheduleJob);  scheduler.rescheduleJob(triggerKey, trigger);  // 如果该定时器处于暂停状态  if(scheduleJob.getStatus() == 1){  pauseJob(scheduler, scheduleJob.getJobId());  } } catch (SchedulerException e) {  throw new RuntimeException("updateJob Fail",e) ; } } /** * 停止定时器 */ public static void pauseJob (Scheduler scheduler,Long jobId){ try {  scheduler.pauseJob(getJobKey(jobId)); } catch (SchedulerException e){  throw new RuntimeException("pauseJob Fail",e) ; } } /** * 恢复定时器 */ public static void resumeJob (Scheduler scheduler,Long jobId){ try {  scheduler.resumeJob(getJobKey(jobId)); } catch (SchedulerException e){  throw new RuntimeException("resumeJob Fail",e) ; } } /** * 删除定时器 */ public static void deleteJob (Scheduler scheduler,Long jobId){ try {  scheduler.deleteJob(getJobKey(jobId)); } catch (SchedulerException e){  throw new RuntimeException("deleteJob Fail",e) ; } } /** * 执行定时器 */ public static void run (Scheduler scheduler, ScheduleJobBean scheduleJob){ try {  JobDataMap dataMap = new JobDataMap() ;  dataMap.put(ScheduleJobBean.JOB_PARAM_KEY,scheduleJob);  scheduler.triggerJob(getJobKey(scheduleJob.getJobId()),dataMap); } catch (SchedulerException e){  throw new RuntimeException("run Fail",e) ; } }}

4、定时器执行和日志

import com.quart.job.entity.ScheduleJobBean;import com.quart.job.entity.ScheduleJobLogBean;import com.quart.job.service.ScheduleJobLogService;import org.quartz.JobExecutionContext;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.quartz.QuartzJobBean;import java.lang.reflect.Method;import java.util.Date;/** * 定时器执行日志记录 */public class TaskJobLog extends QuartzJobBean { private static final Logger LOG = LoggerFactory.getLogger(TaskJobLog.class) ; @Override protected void executeInternal(JobExecutionContext context) { ScheduleJobBean jobBean = (ScheduleJobBean)context.getMergedJobDataMap().get(ScheduleJobBean.JOB_PARAM_KEY) ; ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService)SpringContextUtil.getBean("scheduleJobLogService") ; // 定时器日志记录 ScheduleJobLogBean logBean = new ScheduleJobLogBean () ; logBean.setJobId(jobBean.getJobId()); logBean.setBeanName(jobBean.getBeanName()); logBean.setParams(jobBean.getParams()); logBean.setCreateTime(new Date()); long beginTime = System.currentTimeMillis() ; try {  // 加载并执行定时器的 run 方法  Object target = SpringContextUtil.getBean(jobBean.getBeanName());  Method method = target.getClass().getDeclaredMethod("run", String.class);  method.invoke(target, jobBean.getParams());  long executeTime = System.currentTimeMillis() - beginTime;  logBean.setTimes((int)executeTime);  logBean.setStatus(0);  LOG.info("定时器 === >> "+jobBean.getJobId()+"执行成功,耗时 === >> " + executeTime); } catch (Exception e){  // 异常信息  long executeTime = System.currentTimeMillis() - beginTime;  logBean.setTimes((int)executeTime);  logBean.setStatus(1);  logBean.setError(e.getMessage()); } finally {  scheduleJobLogService.insert(logBean) ; } }}

三、定时器服务封装

1、定时器初始化

@Servicepublic class ScheduleJobServiceImpl implements ScheduleJobService { @Resource private Scheduler scheduler ; @Resource private ScheduleJobMapper scheduleJobMapper ; /** * 定时器初始化 */ @PostConstruct public void init (){ ScheduleJobExample example = new ScheduleJobExample() ; List scheduleJobBeanList = scheduleJobMapper.selectByExample(example) ; for (ScheduleJobBean scheduleJobBean : scheduleJobBeanList) {  CronTrigger cronTrigger = ScheduleUtil.getCronTrigger(scheduler,scheduleJobBean.getJobId()) ;  if (cronTrigger == null){  ScheduleUtil.createJob(scheduler,scheduleJobBean);  } else {  ScheduleUtil.updateJob(scheduler,scheduleJobBean);  } } }}

2、添加定时器

@Override@Transactional(rollbackFor = Exception.class)public int insert(ScheduleJobBean record) { ScheduleUtil.createJob(scheduler,record); return scheduleJobMapper.insert(record);}

3、立即执行一次定时器

@Override@Transactional(rollbackFor = Exception.class)public void run(Long jobId) { ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ; ScheduleUtil.run(scheduler,scheduleJobBean);}

4、更新定时器

@Override@Transactional(rollbackFor = Exception.class)public int updateByPrimaryKeySelective(ScheduleJobBean record) { ScheduleUtil.updateJob(scheduler,record); return scheduleJobMapper.updateByPrimaryKeySelective(record);}

5、停止定时器

@Override@Transactional(rollbackFor = Exception.class)public void pauseJob(Long jobId) { ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ; ScheduleUtil.pauseJob(scheduler,jobId); scheduleJobBean.setStatus(1); scheduleJobMapper.updateByPrimaryKeySelective(scheduleJobBean) ;}

6、恢复定时器

@Override@Transactional(rollbackFor = Exception.class)public void resumeJob(Long jobId) { ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ; ScheduleUtil.resumeJob(scheduler,jobId); scheduleJobBean.setStatus(0); scheduleJobMapper.updateByPrimaryKeySelective(scheduleJobBean) ;}

7、删除定时器

@Override@Transactional(rollbackFor = Exception.class)public void delete(Long jobId) { ScheduleUtil.deleteJob(scheduler, jobId); scheduleJobMapper.deleteByPrimaryKey(jobId) ;}

四、配置一个测试的定时器

1、定时接口封装

public interface TaskService { void run(String params);}

2、测试定时器

@Component("getTimeTask")public class GetTimeTask implements TaskService { private static final Logger LOG = LoggerFactory.getLogger(GetTimeTask.class.getName()) ; private static final SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ; @Override public void run(String params) { LOG.info("Params === >> " + params); LOG.info("当前时间::::"+format.format(new Date())); }}

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...