Spring Boot 2 整合 QuartJob 实现定时器实时管理功能

一、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.RELEASE
quart-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;
@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;
 }
}

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、定时器初始化

@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);
  }
 }
 }
}

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()));
 }
}

五、源代码

GitHub:知了一笑

https://github.com/cicadasmile/middle-ware-parent

总结

以上所述是小编给大家介绍的Spring Boot 2 整合 QuartJob 实现定时器实时管理功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • SpringBoot集成ElaticJob定时器的实现代码

    本文介绍了SpringBoot集成ElaticJob定时器的实现代码,分享给大家,具体如下: POM文件配置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:sch

  • SpringBoot 动态定时器的使用方法

    SpringBoot使用定时器使用方法添加@Scheduled注解 设计cron参数即可 package com.clsystem.Comm; import org.springframework.scheduling.annotation.Scheduled; /** * Created by pudding on 2017-11-10.(打卡记录定时任务) */ @Component public class ClockTiming { /** * 定时器 */ @Scheduled(cro

  • Spring Boot 2 整合 QuartJob 实现定时器实时管理功能

    一.QuartJob简介 1.一句话描述 Quartz是一个完全由java编写的开源作业调度框架,形式简易,功能强大. 2.核心API (1).Scheduler 代表一个 Quartz 的独立运行容器,Scheduler 将 Trigger 绑定到特定 JobDetail, 这样当 Trigger 触发时, 对应的 Job 就会被调度. (2).Trigger 描述 Job 执行的时间触发规则.主要有 SimpleTrigger 和 CronTrigger 两个子类,通过一个 TriggerK

  • 关于Spring Boot WebSocket整合以及nginx配置详解

    前言 本文主要给大家介绍了关于Spring Boot WebSocket整合及nginx配置的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一:Spring Boot WebSocket整合 创建一个maven项目,加入如下依赖 <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId>

  • Spring boot怎么整合Mybatis

    最近刚接触spring boot,正是因为他的及简配置方便开发,促使我下定决心要用它把之前写的项目重构,那么问题来了,spring boot怎么整合mybatis呢,下面几个配置类来搞定. 在我的代码当中是实现了数据库读写分离的,所以代码仅做参考,如有需要可以加我微信:benyzhous [后续更新] 1.文件结构 DataBaseConfiguration.Java用来获取数据库连接配置信息,配置从application.properties中读取 MybatisConfiguration.j

  • Spring Boot + Kotlin整合MyBatis的方法教程

    前言 最近使用jpa比较多,再看看mybatis的xml方式写sql觉得不爽,接口定义与映射离散在不同文件中,使得阅读起来并不是特别方便. 因此使用Spring Boot去整合MyBatis,在注解里写sql 参考<我的第一个Kotlin应用> 创建项目,在build.gradle文件中引入依赖 compile "org.mybatis.spring.boot:mybatis-spring-boot-starter:$mybatis_version" compile &qu

  • Spring boot Mybatis 整合(完整版)

    本项目使用的环境: 开发工具: Intellij IDEA 2017.1.3 springboot: 1.5.6 jdk:1.8.0_161 maven:3.3.9 额外功能 PageHelper 分页插件 mybatis generator 自动生成代码插件 步骤: 1.创建一个springboot项目: 2.创建项目的文件结构以及jdk的版本 3.选择项目所需要的依赖 然后点击finish 5.看一下文件的结构: 6.查看一下pom.xml: <?xml version="1.0&qu

  • Spring Boot/Angular整合Keycloak实现单点登录功能

    Keycloak Keycloak为现代应用和服务提供开源的认证和访问管理,即通常所说的认证和授权.Keycloak支持OpenID.OAuth 2.0和SAML 2.0协议:支持用户注册.用户管理.权限管理:支持代理OpenID.SAML 2.0 IDP,支持GitHub.LinkedIn等第三方登录,支持整合LDAP和Active Directory:支持自定义认证流程.自定义用户界面,支持国际化. Keycloak支持Java.C#.Python.Android.iOS.JavaScrip

  • spring boot 2整合swagger-ui过程解析

    这篇文章主要介绍了spring boot 2整合swagger-ui过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.添加mvn依赖 修改pom.xml加入 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.5.0</v

  • 从零搭建Spring Boot脚手架整合OSS作为文件服务器的详细教程

    1. 前言 文件服务器是一个应用必要的组件之一.最早我搞过FTP,然后又用过FastDFS,接私活的时候我用MongoDB也凑合凑合.现如今时代不同了,开始流行起了OSS. Gitee: https://gitee.com/felord/kono day06 分支 欢迎Star GitHub: https://github.com/NotFound403/kono day06 分支 欢迎Star 2. 什么是OSS 全称为Object Storage Service,也叫对象存储服务,是一种解决

  • Spring Boot 如何整合连接池

    Spring Boot 整合连接池 在实际开发中应用程序与数据库交互时,"获得连接"或在"释放资源"是非常消耗资源的两个过程,为了解决如此类性能问题,通常这种情况我们采用连接池技术重用连接Connection对象,如图1所示. 图-1 其实Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口.然后我们的应用程序中耦合这个接口,便可以方便的切换不同厂商的连接池,常见的连接池有DBCP.C3P0.DRU

  • Spring Boot 优雅整合多数据源

    目录 何时用到多数据源 整合单一的数据源 整合Mybatis 多数据源如何整合? 什么是动态数据源? 数据源切换如何保证线程隔离? 如何构造一个动态数据源? 定义一个注解 如何与Mybatis整合? 演示 总结 前言: 什么是多数据源?最常见的单一应用中最多涉及到一个数据库,即是一个数据源(Datasource).那么顾名思义,多数据源就是在一个单一应用中涉及到了两个及以上的数据库了. 其实在配置数据源的时候就已经很明确这个定义了,如以下代码: @Bean(name = "dataSource&

随机推荐