spring中使用quartz框架(持久化到数据库+springboot)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: spring中使用quartz框架(持久化到数据库+springboot)http://www.bieryun.com/1513.html 本例是在springboot中通过读取数据库的定时任务信息,动态生成quartz定时任务 1、导入依赖: [html] view plai...

spring中使用quartz框架(持久化到数据库+springboot)

本例是在springboot中通过读取数据库的定时任务信息,动态生成quartz定时任务

1、导入依赖:

[html] view plain copy

  1. <dependency>
  2.             <groupId>org.quartz-scheduler</groupId>
  3.             <artifactId>quartz</artifactId>
  4.             <version>2.2.1</version>
  5.         </dependency>
  6.         <dependency>
  7.              <groupId>org.springframework</groupId>
  8.              <artifactId>spring-context-support</artifactId>
  9.              <version>${spring.version}</version>
  10.         </dependency>

2、在项目中添加quartz.properties文件(这样就不会走它自带的properties文件)

[html] view plain copy

  1. # Default Properties file for use by StdSchedulerFactory
  2. # to create a Quartz Scheduler Instance, if a different
  3. # properties file is not explicitly specified.
  4. #
  5. #默认或是自己改名字都行
  6. org.quartz.scheduler.instanceName: DefaultQuartzScheduler
  7. #如果使用集群,instanceId必须唯一,设置成AUTO
  8. org.quartz.scheduler.instanceId = AUTO
  9. org.quartz.scheduler.rmi.export: false
  10. org.quartz.scheduler.rmi.proxy: false
  11. org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
  12. org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
  13. org.quartz.threadPool.threadCount: 10
  14. org.quartz.threadPool.threadPriority: 5
  15. org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
  16. org.quartz.jobStore.misfireThreshold: 60000
  17. #============================================================================
  18. # Configure JobStore
  19. #============================================================================
  20. #
  21. #org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
  22. #存储方式使用JobStoreTX,也就是数据库
  23. org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
  24. org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
  25. #使用自己的配置文件
  26. org.quartz.jobStore.useProperties:true
  27. #数据库中quartz表的表名前缀
  28. org.quartz.jobStore.tablePrefix:qrtz_
  29. org.quartz.jobStore.dataSource:qzDS
  30. #是否使用集群(如果项目只部署到 一台服务器,就不用了)
  31. org.quartz.jobStore.isClustered = true
  32. #============================================================================
  33. # Configure Datasources
  34. #============================================================================
  35. #配置数据源
  36. org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
  37. org.quartz.dataSource.qzDS.URL:jdbc:mysql://10.4.33.251:3306/ecif_orgin
  38. org.quartz.dataSource.qzDS.user:reader1
  39. org.quartz.dataSource.qzDS.password:Reader12341
  40. org.quartz.dataSource.qzDS.maxConnection:10

 

3、在数据库中创建quartz相关的表

1)进入quartz的官网http://www.quartz-scheduler.org/,点击Downloads,下载后在目录\docs\dbTables下有常用数据库创建quartz表的脚本。

2)百度去搜创建quartz表

4、自定义MyJobFactory,解决spring不能在quartz中注入bean的问题

[java] view plain copy

  1. package com.nnfe.ecif.domain.bean;
  2. import org.quartz.spi.TriggerFiredBundle;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
  5. import org.springframework.scheduling.quartz.AdaptableJobFactory;
  6. import org.springframework.stereotype.Component;
  7. @Component
  8. public class MyJobFactory extends AdaptableJobFactory {
  9.       @Autowired
  10.       private AutowireCapableBeanFactory capableBeanFactory;
  11.       @Override
  12.       protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
  13.         Object jobInstance = super.createJobInstance(bundle);
  14.         capableBeanFactory.autowireBean(jobInstance); //这一步解决不能spring注入bean的问题
  15.         return jobInstance;
  16.       }
  17. }

5、创建调度器schedule

[java] view plain copy

  1. package com.nnfe.ecif.config;
  2. import java.io.IOException;
  3. import java.util.Properties;
  4. import org.quartz.Scheduler;
  5. import org.quartz.SchedulerException;
  6. import org.quartz.SchedulerFactory;
  7. import org.quartz.impl.StdSchedulerFactory;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.beans.factory.config.PropertiesFactoryBean;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import org.springframework.core.io.ClassPathResource;
  13. import org.springframework.scheduling.quartz.SchedulerFactoryBean;
  14. import com.nnfe.ecif.domain.bean.MyJobFactory;
  15. @Configuration
  16. public class QuartzConfigration {
  17.      @Autowired
  18.      private MyJobFactory myJobFactory;  //自定义的factory

[java] view plain copy

  1. //获取工厂bean 
  2.     @Bean
  3.     public SchedulerFactoryBean schedulerFactoryBean() {
  4.       SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
  5.       try {
  6.         schedulerFactoryBean.setQuartzProperties(quartzProperties());
  7.         schedulerFactoryBean.setJobFactory(myJobFactory);
  8.     } catch (IOException e) {
  9.         // TODO Auto-generated catch block
  10.         e.printStackTrace();
  11.     }
  12.       return schedulerFactoryBean;
  13.     }

[java] view plain copy

  1. //指定quartz.properties
  2.     @Bean
  3.     public Properties quartzProperties() throws IOException {
  4.         PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
  5.         propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
  6.         propertiesFactoryBean.afterPropertiesSet();
  7.         return propertiesFactoryBean.getObject();
  8.     }
  9. //创建schedule  
  10.     @Bean(name = "scheduler")
  11.     public Scheduler scheduler() {
  12.       return schedulerFactoryBean().getScheduler();
  13.     }
  14. }

 

6、更新quartz中的任务

首先我们需要自己创建一张表,用来存放trigger的信息,然后从数据库读取这些信息来随时更新定时任务

现在我的数据库中有两个定时任务,注意:job_name存放的任务类的全路径,在quartz中通过jobName和jobGroup来确定trigger的唯一性,所以这两列为联合唯一索引。

接着创建实体类:

[java] view plain copy

  1. import javax.persistence.Column;
  2. import javax.persistence.Entity;
  3. import javax.persistence.GeneratedValue;
  4. import javax.persistence.GenerationType;
  5. import javax.persistence.Id;
  6. import javax.persistence.Table;
  7. import org.hibernate.annotations.GenericGenerator;
  8. @Entity
  9. @Table(name = "c_schedule_triggers")
  10. public class CScheduleTrigger {
  11.     @Id
  12.     @GenericGenerator(name = "mysqlNative", strategy = "native")
  13.     @GeneratedValue(generator = "mysqlNative")
  14.       private Integer id;
  15.       @Column
  16.       private String cron;  //时间表达式
  17.       private String status; //使用状态 0:禁用   1:启用
  18.       private String jobName; //任务名称
  19.       private String jobGroup; //任务分组

 

更新quartz中的任务

[html] view plain copy

  1. package com.nnfe.ecif.domain.service.impl;
  2. import java.util.List;
  3. import org.quartz.CronScheduleBuilder;
  4. import org.quartz.CronTrigger;
  5. import org.quartz.Job;
  6. import org.quartz.JobBuilder;
  7. import org.quartz.JobDetail;
  8. import org.quartz.JobKey;
  9. import org.quartz.Scheduler;
  10. import org.quartz.TriggerBuilder;
  11. import org.quartz.TriggerKey;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.context.annotation.Configuration;
  16. import org.springframework.scheduling.annotation.EnableScheduling;
  17. import org.springframework.scheduling.annotation.Scheduled;
  18. import org.springframework.stereotype.Component;
  19. import org.springframework.stereotype.Service;
  20. import com.nnfe.ecif.domain.orm.w.CScheduleTriggerRepository;
  21. import com.nnfe.ecif.domain.orm.w.CScheduleTrigger;
  22. import com.nnfe.ecif.domain.service.ScheduleTriggerService;
  23. @Service
  24. public class ScheduleTriggerServiceImpl implements ScheduleTriggerService{
  25.     private static final Logger logger =  LoggerFactory.getLogger(ScheduleTriggerServiceImpl.class);
  26.     @Autowired
  27.     private Scheduler scheduler;
  28.     @Autowired
  29.     private CScheduleTriggerRepository triggerRepository;
  30.     @Override
  31.     @Scheduled(cron="0 0 23:00 * * ?")  //每天晚上11点调用这个方法来更新quartz中的任务
  32.     public void refreshTrigger() {
  33.         try {
  34.             //查询出数据库中所有的定时任务
  35.             List<CScheduleTrigger> jobList = triggerRepository.queryAll();
  36.             if(jobList!=null){
  37.                 for(CScheduleTrigger scheduleJob : jobList){
  38.                     String status = scheduleJob.getStatus(); //该任务触发器目前的状态
  39.                     TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  40.                     CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
  41.                      //说明本条任务还没有添加到quartz中
  42.                     if (null == trigger) {
  43.                         if(status.equals("0")){ //如果是禁用,则不用创建触发器
  44.                             continue;
  45.                         }
  46.                         JobDetail jobDetail=null;
  47.                         try {
  48.                             //创建JobDetail(数据库中job_name存的任务全路径,这里就可以动态的把任务注入到JobDetail中)
  49.                             jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(scheduleJob.getJobName()))
  50.                                 .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
  51.                             //表达式调度构建器
  52.                             CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob
  53.                                 .getCron());
  54.                             //按新的cronExpression表达式构建一个新的trigger
  55.                             trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).withSchedule(scheduleBuilder).build();
  56.                             //把trigger和jobDetail注入到调度器
  57.                             scheduler.scheduleJob(jobDetail, trigger);
  58.                         } catch (ClassNotFoundException e) {
  59.                             // TODO Auto-generated catch block
  60.                             e.printStackTrace();
  61.                         }
  62.                     } else {  //说明查出来的这条任务,已经设置到quartz中了
  63.                         // Trigger已存在,先判断是否需要删除,如果不需要,再判定是否时间有变化
  64.                         if(status.equals("0")){ //如果是禁用,从quartz中删除这条任务
  65.                             JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  66.                             scheduler.deleteJob(jobKey);
  67.                             continue;
  68.                         }
  69.                         String searchCron = scheduleJob.getCron(); //获取数据库的
  70.                         String currentCron = trigger.getCronExpression();
  71.                         if(!searchCron.equals(currentCron)){  //说明该任务有变化,需要更新quartz中的对应的记录
  72.                             //表达式调度构建器
  73.                             CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron);
  74.                             //按新的cronExpression表达式重新构建trigger
  75.                             trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
  76.                                 .withSchedule(scheduleBuilder).build();
  77.                             //按新的trigger重新设置job执行
  78.                             scheduler.rescheduleJob(triggerKey, trigger);
  79.                         }
  80.                     }
  81.                 }
  82.             }
  83.         } catch (Exception e) {
  84.            logger.error("定时任务每日刷新触发器任务异常,在ScheduleTriggerServiceImpl的方法refreshTrigger中,异常信息:",e);
  85.         }
  86.     }

 

7、自定义任务

[html] view plain copy

  1. @Component
  2. public class MyTask1 implements Job{
  3.     //这里就可以通过spring注入bean了
  4.     @Autowired
  5.     private CScheduleTriggerRepository jobRepository;
  6.     @Autowired
  7.     private CScheduleRecordsRepository recordsRepository;
  8.     @Override
  9.     public void execute(JobExecutionContext context)
  10.             throws JobExecutionException {
  11.         boolean isExecute = false;  //是否已执行业务逻辑
  12.         boolean flag = false;  //业务逻辑执行后返回结果
  13.         try{
  14.             //可以通过context拿到执行当前任务的quartz中的很多信息,如当前是哪个trigger在执行该任务
  15.             CronTrigger trigger = (CronTrigger) context.getTrigger();
  16.             String corn = trigger.getCronExpression();
  17.             String jobName = trigger.getKey().getName();
  18.             String jobGroup = trigger.getKey().getGroup();

 

要搞清楚一个问题:从数据库读取任务信息动态生成定时任务,和把quartz持久化到数据库是没有关系的。

前者是我们自己定义的业务表,而后者是quartz使用自己的表来存储信息。持久化到数据库后,就算服务器重启或是多个quartz节点也没关系,因为他们共享数据库中的任务信息。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
22天前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
41 4
SpringBoot入门(4) - 添加内存数据库H2
|
22天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
17天前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
57 13
|
11天前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
27 4
|
18天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
36 2
|
18天前
|
消息中间件 NoSQL Java
springboot整合常用中间件框架案例
该项目是Spring Boot集成整合案例,涵盖多种中间件的使用示例,每个案例项目使用最小依赖,便于直接应用到自己的项目中。包括MyBatis、Redis、MongoDB、MQ、ES等的整合示例。
70 1
|
13天前
|
存储 安全 Java
springboot当中ConfigurationProperties注解作用跟数据库存入有啥区别
`@ConfigurationProperties`注解和数据库存储配置信息各有优劣,适用于不同的应用场景。`@ConfigurationProperties`提供了类型安全和模块化的配置管理方式,适合静态和简单配置。而数据库存储配置信息提供了动态更新和集中管理的能力,适合需要频繁变化和集中管理的配置需求。在实际项目中,可以根据具体需求选择合适的配置管理方式,或者结合使用这两种方式,实现灵活高效的配置管理。
10 0
|
9天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
24 1
|
11天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
26 4
|
18天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
85 1