经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
SpringBoot2.0 整合 QuartJob ,实现定时器实时管理
来源:cnblogs  作者:知了一笑  时间:2019/6/6 9:21:36  对本文有异议

一、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、项目结构


版本描述

  1. spring-boot2.1.3.RELEASE
  2. quart-job2.3.0

2、定时器配置

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

3、定时器管理工具

  1. import com.quart.job.entity.ScheduleJobBean;
  2. import org.quartz.*;
  3. /**
  4. * 定时器工具类
  5. */
  6. public class ScheduleUtil {
  7. private ScheduleUtil (){}
  8. private static final String SCHEDULE_NAME = "HUSKY_" ;
  9. /**
  10. * 触发器 KEY
  11. */
  12. public static TriggerKey getTriggerKey(Long jobId){
  13. return TriggerKey.triggerKey(SCHEDULE_NAME+jobId) ;
  14. }
  15. /**
  16. * 定时器 Key
  17. */
  18. public static JobKey getJobKey (Long jobId){
  19. return JobKey.jobKey(SCHEDULE_NAME+jobId) ;
  20. }
  21. /**
  22. * 表达式触发器
  23. */
  24. public static CronTrigger getCronTrigger (Scheduler scheduler,Long jobId){
  25. try {
  26. return (CronTrigger)scheduler.getTrigger(getTriggerKey(jobId)) ;
  27. } catch (SchedulerException e){
  28. throw new RuntimeException("getCronTrigger Fail",e) ;
  29. }
  30. }
  31. /**
  32. * 创建定时器
  33. */
  34. public static void createJob (Scheduler scheduler, ScheduleJobBean scheduleJob){
  35. try {
  36. // 构建定时器
  37. JobDetail jobDetail = JobBuilder.newJob(TaskJobLog.class).withIdentity(getJobKey(scheduleJob.getJobId())).build() ;
  38. CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
  39. .cronSchedule(scheduleJob.getCronExpression())
  40. .withMisfireHandlingInstructionDoNothing() ;
  41. CronTrigger trigger = TriggerBuilder.newTrigger()
  42. .withIdentity(getTriggerKey(scheduleJob.getJobId()))
  43. .withSchedule(scheduleBuilder).build() ;
  44. jobDetail.getJobDataMap().put(ScheduleJobBean.JOB_PARAM_KEY,scheduleJob);
  45. scheduler.scheduleJob(jobDetail,trigger) ;
  46. // 如果该定时器处于暂停状态
  47. if (scheduleJob.getStatus() == 1){
  48. pauseJob(scheduler,scheduleJob.getJobId()) ;
  49. }
  50. } catch (SchedulerException e){
  51. throw new RuntimeException("createJob Fail",e) ;
  52. }
  53. }
  54. /**
  55. * 更新定时任务
  56. */
  57. public static void updateJob(Scheduler scheduler, ScheduleJobBean scheduleJob) {
  58. try {
  59. // 构建定时器
  60. TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId());
  61. CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
  62. .withMisfireHandlingInstructionDoNothing();
  63. CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId());
  64. trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
  65. trigger.getJobDataMap().put(ScheduleJobBean.JOB_PARAM_KEY, scheduleJob);
  66. scheduler.rescheduleJob(triggerKey, trigger);
  67. // 如果该定时器处于暂停状态
  68. if(scheduleJob.getStatus() == 1){
  69. pauseJob(scheduler, scheduleJob.getJobId());
  70. }
  71. } catch (SchedulerException e) {
  72. throw new RuntimeException("updateJob Fail",e) ;
  73. }
  74. }
  75. /**
  76. * 停止定时器
  77. */
  78. public static void pauseJob (Scheduler scheduler,Long jobId){
  79. try {
  80. scheduler.pauseJob(getJobKey(jobId));
  81. } catch (SchedulerException e){
  82. throw new RuntimeException("pauseJob Fail",e) ;
  83. }
  84. }
  85. /**
  86. * 恢复定时器
  87. */
  88. public static void resumeJob (Scheduler scheduler,Long jobId){
  89. try {
  90. scheduler.resumeJob(getJobKey(jobId));
  91. } catch (SchedulerException e){
  92. throw new RuntimeException("resumeJob Fail",e) ;
  93. }
  94. }
  95. /**
  96. * 删除定时器
  97. */
  98. public static void deleteJob (Scheduler scheduler,Long jobId){
  99. try {
  100. scheduler.deleteJob(getJobKey(jobId));
  101. } catch (SchedulerException e){
  102. throw new RuntimeException("deleteJob Fail",e) ;
  103. }
  104. }
  105. /**
  106. * 执行定时器
  107. */
  108. public static void run (Scheduler scheduler, ScheduleJobBean scheduleJob){
  109. try {
  110. JobDataMap dataMap = new JobDataMap() ;
  111. dataMap.put(ScheduleJobBean.JOB_PARAM_KEY,scheduleJob);
  112. scheduler.triggerJob(getJobKey(scheduleJob.getJobId()),dataMap);
  113. } catch (SchedulerException e){
  114. throw new RuntimeException("run Fail",e) ;
  115. }
  116. }
  117. }

4、定时器执行和日志

  1. import com.quart.job.entity.ScheduleJobBean;
  2. import com.quart.job.entity.ScheduleJobLogBean;
  3. import com.quart.job.service.ScheduleJobLogService;
  4. import org.quartz.JobExecutionContext;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.scheduling.quartz.QuartzJobBean;
  8. import java.lang.reflect.Method;
  9. import java.util.Date;
  10. /**
  11. * 定时器执行日志记录
  12. */
  13. public class TaskJobLog extends QuartzJobBean {
  14. private static final Logger LOG = LoggerFactory.getLogger(TaskJobLog.class) ;
  15. @Override
  16. protected void executeInternal(JobExecutionContext context) {
  17. ScheduleJobBean jobBean = (ScheduleJobBean)context.getMergedJobDataMap().get(ScheduleJobBean.JOB_PARAM_KEY) ;
  18. ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService)SpringContextUtil.getBean("scheduleJobLogService") ;
  19. // 定时器日志记录
  20. ScheduleJobLogBean logBean = new ScheduleJobLogBean () ;
  21. logBean.setJobId(jobBean.getJobId());
  22. logBean.setBeanName(jobBean.getBeanName());
  23. logBean.setParams(jobBean.getParams());
  24. logBean.setCreateTime(new Date());
  25. long beginTime = System.currentTimeMillis() ;
  26. try {
  27. // 加载并执行定时器的 run 方法
  28. Object target = SpringContextUtil.getBean(jobBean.getBeanName());
  29. Method method = target.getClass().getDeclaredMethod("run", String.class);
  30. method.invoke(target, jobBean.getParams());
  31. long executeTime = System.currentTimeMillis() - beginTime;
  32. logBean.setTimes((int)executeTime);
  33. logBean.setStatus(0);
  34. LOG.info("定时器 === >> "+jobBean.getJobId()+"执行成功,耗时 === >> " + executeTime);
  35. } catch (Exception e){
  36. // 异常信息
  37. long executeTime = System.currentTimeMillis() - beginTime;
  38. logBean.setTimes((int)executeTime);
  39. logBean.setStatus(1);
  40. logBean.setError(e.getMessage());
  41. } finally {
  42. scheduleJobLogService.insert(logBean) ;
  43. }
  44. }
  45. }

三、定时器服务封装

1、定时器初始化

  1. @Service
  2. public class ScheduleJobServiceImpl implements ScheduleJobService {
  3. @Resource
  4. private Scheduler scheduler ;
  5. @Resource
  6. private ScheduleJobMapper scheduleJobMapper ;
  7. /**
  8. * 定时器初始化
  9. */
  10. @PostConstruct
  11. public void init (){
  12. ScheduleJobExample example = new ScheduleJobExample() ;
  13. List<ScheduleJobBean> scheduleJobBeanList = scheduleJobMapper.selectByExample(example) ;
  14. for (ScheduleJobBean scheduleJobBean : scheduleJobBeanList) {
  15. CronTrigger cronTrigger = ScheduleUtil.getCronTrigger(scheduler,scheduleJobBean.getJobId()) ;
  16. if (cronTrigger == null){
  17. ScheduleUtil.createJob(scheduler,scheduleJobBean);
  18. } else {
  19. ScheduleUtil.updateJob(scheduler,scheduleJobBean);
  20. }
  21. }
  22. }
  23. }

2、添加定时器

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

3、立即执行一次定时器

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

4、更新定时器

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

5、停止定时器

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

6、恢复定时器

  1. @Override
  2. @Transactional(rollbackFor = Exception.class)
  3. public void resumeJob(Long jobId) {
  4. ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ;
  5. ScheduleUtil.resumeJob(scheduler,jobId);
  6. scheduleJobBean.setStatus(0);
  7. scheduleJobMapper.updateByPrimaryKeySelective(scheduleJobBean) ;
  8. }

7、删除定时器

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

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

1、定时接口封装

  1. public interface TaskService {
  2. void run(String params);
  3. }

2、测试定时器

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

五、源代码

  1. GitHub:知了一笑
  2. https://github.com/cicadasmile/middle-ware-parent

原文链接:http://www.cnblogs.com/cicada-smile/p/10982050.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号