(六)整合 QuartJob ,实现定时器实时管理
整合 QuartJob ,实现定时器实时管理
1、QuartJob简介
Quartz是一个完全由java编写的开源作业调度框架,形式简易,功能强大。
1.1 核心API
- Scheduler
代表一个 Quartz 的独立运行容器,Scheduler 将 Trigger 绑定到特定 JobDetail, 这样当 Trigger 触发时, 对应的 Job 就会被调度。 - Trigger
描述 Job 执行的时间触发规则。主要有 SimpleTrigger 和 CronTrigger 两个子类,通过一个 TriggerKey 唯一标识。 - Job
定义一个任务,规定了任务是执行时的行为。JobExecutionContext 提供了调度器的上下文信息,Job 的数据可从 JobDataMap 中获取。 - JobDetail
Quartz 在每次执行 Job 时,都重新创建一个 Job 实例,所以它不直接接受一个 Job 的实例,相反它接收一个 Job 实现类。描述 Job 的实现类及其它相关的静态信息,如 Job 名字、描述等。
2、SpringBoot整合QuartJob
2.1 项目结构
版本描述
spring-boot:2.1.3.RELEASE
quart-job:2.3.0
2.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;
@Configuration
public 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;
}
}
2.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) ;
}
}
}
2.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) ;
}
}
}
3、定时器服务封装
3.1 定时器初始化
@Service
public class ScheduleJobServiceImpl implements ScheduleJobService {
@Resource
private Scheduler scheduler ;
@Resource
private ScheduleJobMapper scheduleJobMapper ;
/**
* 定时器初始化
*/
@PostConstruct
public void init (){
ScheduleJobExample example = new ScheduleJobExample() ;
List<ScheduleJobBean> 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);
}
}
}
}
3.2 添加定时器
@Override
@Transactional(rollbackFor = Exception.class)
public int insert(ScheduleJobBean record) {
ScheduleUtil.createJob(scheduler,record);
return scheduleJobMapper.insert(record);
}
3.3 立即执行一次定时器
@Override
@Transactional(rollbackFor = Exception.class)
public void run(Long jobId) {
ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ;
ScheduleUtil.run(scheduler,scheduleJobBean);
}
3.4 更新定时器
@Override
@Transactional(rollbackFor = Exception.class)
public int updateByPrimaryKeySelective(ScheduleJobBean record) {
ScheduleUtil.updateJob(scheduler,record);
return scheduleJobMapper.updateByPrimaryKeySelective(record);
}
3.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) ;
}
3.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) ;
}
3.7 删除定时器
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(Long jobId) {
ScheduleUtil.deleteJob(scheduler, jobId);
scheduleJobMapper.deleteByPrimaryKey(jobId) ;
}
4、配置一个测试的定时器
4.1 定时接口封装
public interface TaskService {
void run(String params);
}
4.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()));
}
}
(六)整合 QuartJob ,实现定时器实时管理的更多相关文章
- SpringBoot2.0 整合 QuartJob ,实现定时器实时管理
一.QuartJob简介 1.一句话描述 Quartz是一个完全由java编写的开源作业调度框架,形式简易,功能强大. 2.核心API (1).Scheduler 代表一个 Quartz 的独立运行容 ...
- (六)boost库之内存管理shared_ptr
(六)boost库之内存管理shared_ptr 1.shared_ptr的基本用法 boost::shared_ptr<int> sp(new int(10)); //一个指向整数的sh ...
- Shiro 整合SpringMVC 并实现权限管理,登录和注销
Shiro 整合SpringMVC 并且实现权限管理,登录和注销 Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring S ...
- Linux第六周学习总结——进程额管理和进程的创建
Linux第六周学习总结--进程额管理和进程的创建 作者:刘浩晨 [原创作品转载请注明出处] <Linux内核分析>MOOC课程http://mooc.study.163.com/cour ...
- 使用spring整合Quartz实现—定时器
使用spring整合Quartz实现—定时器(Maven项目做演示) 不基于特定的基类的方法 一,开发环境以及依赖的jar包 Spring 4.2.6.RELEASE Maven 3.3.9 Jdk ...
- Spring Boot 学习笔记(六) 整合 RESTful 参数传递
Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...
- SpringBoot非官方教程 | 第二十六篇: sprinboot整合elk,搭建实时日志平台
转载请标明出处: 原文首发于https://www.fangzhipeng.com/springboot/2017/07/11/sprinboot25-elk/ 本文出自方志朋的博客 这篇文章主要介绍 ...
- springBoot整合spring security实现权限管理(单体应用版)--筑基初期
写在前面 在前面的学习当中,我们对spring security有了一个小小的认识,接下来我们整合目前的主流框架springBoot,实现权限的管理. 在这之前,假定你已经了解了基于资源的权限管理模型 ...
- (stm32f103学习总结)—RTC独立定时器—实时时钟实验
一.STM32F1 RTC介绍 1.1 RTC简介 STM32 的实时时钟( RTC)是一个独立的定时器. STM32 的 RTC 模 块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的 ...
随机推荐
- 【C】C语言位域(位段)详解
作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14215449.html 目录 一.位域是什么? 二.位域的存储 2.1 相邻成员的类型相同 2.2 相邻成员的类 ...
- 如何理解SQL的可重复读和幻读之间的区别?
从本源来理解比较容易理解,如果只是描述概念和定义,容易让人云里雾里找不到方向.正好这两天在浏览mysql的文档,我可以简单在这里总结一下,帮助其他还没有理解的朋友,如果有错误也麻烦帮忙指正. 先讲一点 ...
- 树莓派4B智能小车机器套件——入手组装实验记录
树莓派4B智能小车机器套件--入手组装实验记录 4WD智能小车(4WD SMART ROBOT KIT),支持Arduino.51.STM32.Raspberry Pi等4个版本.本套件采用的是树莓派 ...
- Git之pull,fetch差别
简言之, pull=fetch+merge,下拉远程分支并与本地分支合并. fetch只是下拉远程分支,怎么合并,可以自己再做选择. 进一步了解是,git本地有暂存区(亦称为Index区) fetch ...
- Akka Typed 官方文档之随手记
️ 引言 近两年,一直在折腾用FP与OO共存的编程语言Scala,采取以函数式编程为主的方式,结合TDD和BDD的手段,采用Domain Driven Design的方法学,去构造DDDD应用(Dom ...
- OpenTelemetry - 云原生下可观测性的新标准
CNCF 简介 CNCF(Cloud Native Computing Foundation),中文为"云原生计算基金会",CNCF是Linux基金会旗下的基金会,可以理解为一个非 ...
- SpringCloud Alibaba Nacos服务注册与配置管理
Nacos SpringCloud Alibaba Nacos是一个狗抑郁构建云原生应用的动态服务发现.配置管理和服务管理平台. Nacos:Dynamic Naming and Configurat ...
- 怎么判断是旧版本的ext3还是新版本?
怎么判断是旧版本的ext3还是新版本的? ---高性能419
- kubernets集群的安全防护(下)
一 集群角色以及集群角色绑定 1.1 前面我们提到过角色以及角色绑定,那么现在为什么会出现集群级别的角色以及角色绑定,作用有如下所示 我们如果需要在所有的命名的空间创建某个角色或者角色绑定的时候 ...
- 快速查询表中的NULL数据
正常情况下,NULL值是不会放入B-TREE索引的,因此根据IS NULL查询的时候走的通常是全表扫描,如果记录比较少还好,记录比较多,查询会非常耗时 可以通过创建一个索引来解决 CREATE IND ...