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

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 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节点也没关系,因为他们共享数据库中的任务信息。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
13天前
|
Web App开发 编解码 Java
B/S基层卫生健康云HIS医院管理系统源码 SaaS模式 、Springboot框架
基层卫生健康云HIS系统采用云端SaaS服务的方式提供,使用用户通过浏览器即能访问,无需关注系统的部署、维护、升级等问题,系统充分考虑了模板化、配置化、智能化、扩展化等设计方法,覆盖了基层医疗机构的主要工作流程,能够与监管系统有序对接,并能满足未来系统扩展的需要。
43 4
|
1月前
|
JavaScript 前端开发 Java
基于SpringBoot+Vue实现前后端交互功能(详解Vue框架机制)
基于SpringBoot+Vue实现前后端交互功能(详解Vue框架机制)
|
2月前
|
SQL 开发框架 JavaScript
在 Vue 中进行数据持久化时,有哪些常用的数据库框架?
在 Vue 中进行数据持久化时,有哪些常用的数据库框架?
49 3
|
2月前
|
存储 Java 数据库
|
3月前
|
NoSQL Java Redis
springboot搭建后台框架 (二)整合Redis
springboot搭建后台框架 (二)整合Redis
41 0
|
3月前
|
SQL Java 关系型数据库
springboot搭建后台框架 (一)整合tkMapper
springboot搭建后台框架 (一)整合tkMapper
19 0
|
2月前
|
人工智能 JSON 前端开发
【Spring boot实战】Springboot+对话ai模型整体框架+高并发线程机制处理优化+提示词工程效果展示(按照框架自己修改可对接市面上百分之99的模型)
【Spring boot实战】Springboot+对话ai模型整体框架+高并发线程机制处理优化+提示词工程效果展示(按照框架自己修改可对接市面上百分之99的模型)
|
3月前
|
缓存 安全 Java
Shiro框架以及Spring Boot整合Shiro
Shiro框架以及Spring Boot整合Shiro
Shiro框架以及Spring Boot整合Shiro
|
3天前
|
SQL Java 数据库连接
Springboot框架整合Spring JDBC操作数据
JDBC是Java数据库连接API,用于执行SQL并访问多种关系数据库。它包括一系列Java类和接口,用于建立数据库连接、创建数据库操作对象、定义SQL语句、执行操作并处理结果集。直接使用JDBC涉及七个步骤,包括加载驱动、建立连接、创建对象、定义SQL、执行操作、处理结果和关闭资源。Spring Boot的`spring-boot-starter-jdbc`简化了这些步骤,提供了一个在Spring生态中更便捷使用JDBC的封装。集成Spring JDBC需要添加相关依赖,配置数据库连接信息,并通过JdbcTemplate进行数据库操作,如插入、更新、删除和查询。
|
3天前
|
SQL Java 数据库连接
Springboot框架整合Spring Data JPA操作数据
Spring Data JPA是Spring基于ORM和JPA规范封装的框架,简化了数据库操作,提供增删改查等接口,并可通过方法名自动生成查询。集成到Spring Boot需添加相关依赖并配置数据库连接和JPA设置。基础用法包括定义实体类和Repository接口,通过Repository接口可直接进行数据操作。此外,JPA支持关键字查询,如通过`findByAuthor`自动转换为SQL的`WHERE author=?`查询。