>>分享流行的Java框架以及开源软件,对孙卫琴的《精通Spring:Java Web开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 20421 个阅读者 刷新本主题
 * 贴子主题:  SpringBoot集成Quartz实现定时任务和调度 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2020-03-11 19:59:59     消息  查看  搜索  好友  邮件  复制  引用

     目录:

  1.   SpringBoot集成Quartz

  2.    实现定时任务逻辑

  3.    动态创建定时任务

  4.   Quartz常用类

  5.   Quartz任务熄火策略

  6.   Cron表达式速成

  7.   Quartz使用技巧之   通过JobDataMap和SchedulerContext传递数据

  8.   Spring框架Schedule   功能   的使用方法

               Quartz是开源组织OpenSymphony的一个作业调度框架,采用多线程架构,可伸缩性强,可集群扩展。SpringBoot集成Quartz简单高效,只需实现Job接口,在方法execute()中添加业务逻辑  。

               Spring框架自带了Schedule功能,能满足小型项目对定时任务的功能需求,同样支持Cron表达式、固定间隔、固定频率三种配置方式,但和Quartz相比,不支持任务信息数据库持久化。
    Cron表达式    固定间隔    固定频率    传递数据    任务持久化
    Quartz   √   √   √   √   √
    Spring Schedule   √   √   √   ×   ×


           本文分享SpringBoot集成和配置Quartz的方法,以及在项目中的实际应用方案,最后介绍Spring 框架自带的Schedule功能的用法。

        
    代码文件    功能  要点
    SpringBoot集成Quartz   pom.xml   引入 Quartz 依赖 : spring-boot-starter-quartz
   application.yml   配置Quartz属性,配置Job运行时间cron表达式
   QuartzConfig.java   配置Bean: JobDetail, Trigger,读取cron运行时间配置
    实现定时任务   QuartzJob.java   实现Job接口,或者继承QuartzJobBean类
    动态创建任务   CheckController .java   增加REST接口/chk/job,创建一个Job定时任务,通过Context上下文传递数据。


            项目代码:  https://github.com/jextop/StarterApi/

   示例代码:  https://github.com/rickding/HelloJava/tree/master/HelloQuartz

                 一,SpringBoot集成Quartz

  1.   新建SpringBoot项目时,选中Quartz,将自动添加Quartz依赖。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  2.   已有SpringBoot项目,可以在pom.xml中直接添加Quartz依赖。

  <dependency>
     <groupId> org.springframework.boot </groupId>
     <artifactId> spring-boot-starter-quartz </artifactId>
</dependency>

  3.   在application.yml中配置Quartz,指定任务存储类型:

  memory:内存方式,默认。

  jdbc:数据库持久化方式,将创建数据表并保存任务信息。

  spring:
     quartz:  
          job-store-type: jdbc
        jdbc:  
            initialize-schema: always

  

  job:  
    quartz:  
      cron: 0 0/23 * * *  

            4.  在QuartzConfig.java中配置Bean,声明JobDetail和Trigger,使用cron表达式设置任务运行时间:

  @Configuration
@ConfigurationProperties ( "job.quartz" )
public class  QuartzConfig {
      private  String  cron ;

      @Bean
      public  JobDetail  quartzJob () {
          return  JobBuilder. newJob (QuartzJob. class ).storeDurably().build() ;
      }

      @Bean
      public  Trigger  quartzTrigger () {
         CronScheduleBuilder scheduleBuilder = CronScheduleBuilder. cronSchedule ( cron ) ;

         return  TriggerBuilder. newTrigger ()
                 .forJob(quartzJob())
                 .withSchedule(scheduleBuilder)
                 .build() ;
      }

      public  String  getCron () {
          return  cron ;
      }

      public void  setCron (String cron) {
          this . cron  = cron ;
      }
}

                 二,定时任务QuartzJob.java   ,继承QuartzJobBean类   ,   实现Job接口。

   从JobExecutionContext中读取附加信息,执行业务逻辑。

  点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  public class  QuartzJob  extends  QuartzJobBean {
      @Override
      protected void  executeInternal (JobExecutionContext context)  throws  JobExecutionException {
         LogUtil. info ( "quartz job " , new  Date()) ;

         try  {
             JextService jextService = (JextService) context.getScheduler().getContext().get( "jextService" ) ;
             if  (jextService !=  null ) {
                 jextService.getInfo( true ) ;
              }
         }  catch  (SchedulerException e) {
             LogUtil. info (e.getMessage()) ;
          }
     }
}

                 三,动态创建定时任务

  1.   增加RestController: CheckController.java

  2.   增加REST接口/chk/job,创建一个定时任务,添加附加信息到Scheduler上下文中。

  @GetMapping ( value  =  "/chk/job" )
public  Object  job () {
     JobDetail job = JobBuilder. newJob (QuartzJob. class ).build() ;
      SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder. newTrigger ()
             .forJob(job)
             .startAt( new  Date())
             .build() ;

      Date date =  null;
     try  {
         Scheduler scheduler = StdSchedulerFactory. getDefaultScheduler () ;
          scheduler.getContext().put( "jextService" ,  jextService ) ;

          date = scheduler.scheduleJob(job ,  trigger) ;
          scheduler.startDelayed( 1 ) ;
      }  catch  (SchedulerException e) {
         e.printStackTrace() ;
      }

      final  Date jobDate = date ;
     return new  HashMap<String ,  Object>() {{
         put( "chk" ,  "job" ) ;
          put( "date" ,  jobDate ) ;
      }} ;
}

  3.  Postman调用REST接口创建定时任务示例

  点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

       

   四,Quartz常用类

  Quartz提供的常用类: Scheduler, SchedulerFactory, Job, JobDetail, JobBuilder, Trigger, TriggerBuilder, ScheduleBuilder,UML类图如下:

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  Scheduler时Quartz调度程序的主要接口, 维护一个JobDetails和Triggers的注册表,到触发时间时,调度程序将执行Job。

               调度程序Scheduler实例通过SchedulerFactory工厂创建,有两个实现类DirectSchedulerFactory和StdSchedulerFactory,前者不写入持久化数据库,后者加载quartz.properties属性配置文件,将查找加载当前目录和org.quartz包。

               任务是实现Job接口的一个类,实现方法execute(),可声明属性:

  - @DisallowConcurrentExecution,同时只执行一个实例。

  - @PersisJobDataAfterExecution,正常执行后将JobDataMap备份。

  JobDetail将任务属性传递给Scheduler,通过JobBuilder创建,JobDataMap保存任务实例的状态信息。

               触发器Trigger通过TriggerBuilder创建,结合ScheduleBuilder设置时间规则,可通过JobDataMap传递数据给Job。常用的两种触发器:

  - SimpleTrigger:指定开始时间、结束时间、重复次数、执行间隔。

  - CronTrigger:使用Cron表达式设置时间规则。

                  五,Quartz任务熄火策略

  ScheduleBuilder设置时间规则时,可配置Misfire选项,指定执行失败熄火时的处理规则:
    含义    支持ScheduleBuilder
   IgnoreMisfires   马上执行,比如整点9点失败,系统10:15启动,会马上执行9点10点的任务。   SimpleSchedule

  CronScheduleBuilder

  CalendarIntervalScheduleBuilder

  DailyTimeIntervalScheduleBuilder
   FireNow   立即再次触发   SimpleSchedule
   NowWithExistingCount   立即再次触发,不计入总次数。   SimpleSchedule
   NowWithRemainingCount   立即再次触发,计入总次数。   SimpleSchedule
   NextWithExistingCount   等待下次执行,不计入总次数。   SimpleSchedule
   NextWithRemainingCount   等待下次执行,计入总次数。   SimpleSchedule
   DoNothing   不做任何处理,执行下一次周期。   CronScheduleBuilder

  CalendarIntervalScheduleBuilder

  DailyTimeIntervalScheduleBuilder
   FireAndProceed   合并下一个周期,正常执行。比如整点9点10点失败,系统10:15启动,在11点合并执行一次。   CronScheduleBuilder

  CalendarIntervalScheduleBuilder

  DailyTimeIntervalScheduleBuilder


            六,Cron表达式速成

  Cron表达式是一个字符串,定义时间规则,由6或7个时间域组成,空格分隔 1张表整理清楚含义和规则,并举例常用表达式,放手边速查。
    时间域序号    含义    取值范围    特殊字符
   1   秒Seconds   0-59   ,-*/
   2   分钟Minutes   0-59   ,-*/
   3   小时Hours   0-23   ,-*/
   4   日期DayOfMonth   1-31   ,-*/   L W C
   5   月份Month   1-12   ,-*/ JAN-DEC
   6   星期DayOfWeek   1-7   ,-*/   L C # SUN-SAT
   7   年Year (可选)   1970-2099   ,-*/

   特殊字符含义

  JAN-DEC 月份英语简称

  SUN-SAT 星期英语简称

   星期的1表示星期天,2表示星期一,依次类推

  *   表示取值范围内的所有数字

  / 表示每隔固定时间触发依次,比如0/5表示从0开始每5个单位时间

  -   表示两个数字之间的范围,比如3-7表示3到7之间,包含3和7

  , 表示离散的枚举数字,比如2,3,5,7表示指定的这几个时间

    只能用在日期DayOfMonth和星期DayOfWeek两个域,表示不指定,避免日期和星期的互相影响,比如指定每月的20日,不管是星期几,正确写法是:0 0 0 20  *  ,其中星期只能用 ,如果使用*  将触发错误。

  L 只能用于日期DayOfMonth和星期DayOfWeek,用于日期时表示月份的最后一天,用于星期时不加数字表示周六,加数字表示最后一个周几,比如0 0 0   * 5L表示每月的最后一个星期四

  W 只能用于日期DayOfMonth,表示周一到周五有效工作日,将在离指定日期的最近的有效工作日触发事件。例如在日期使用5W,如果5日是星期六,则将在最近的工作日星期五(4日)触发。如果5日是星期天,则在6日(星期一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近工作日寻找不会跨月份。

  LW 两个字符连用时表示某个月最后一个工作日

  # 只能用于星期DayOfWeek,表示每个月第几个星期几,比如4#2表示第二个星期三

   常用表达式

  0/5  * *   * *    每5秒钟

  0 0/5  * *  *   每5分钟

  0 0 6  * *    每天早上6点

  0 0 9,13,19  * *    每天上午9点,下午1点,晚上7点

  0 0 23-7/2,8  * *    每天晚上11点到早上7点之间的每两个小时,和早上8点

  0 0/30 9-17  * *    朝九晚五工作时间内每半小时

  0 0 9-21   * MON-SAT 表示996每天的每小时

  0 0 7 LW *   每月最后一个工作日早上7点

  0 0 4 1 1   每年的1月1日早上4点

                 七,Quartz使用技巧   之通过JobDataMap和SchedulerContext传递数据

   在Job.execute()方法中实现业务逻辑时,经常需要一些附加信息。Quartz提供了JobExecutionContext上下文传递数据。

  点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  l   通过JobDataMap传递数据

   代码下载:  https://github.com/rickding/HelloJava/tree/master/HelloQuartz

  src/main/java/com/hello/quartz/

  ├── QuartzConfig.java

  ├── QuartzJob.java
    代码文件    功能  要点
    设置数据   QuartzConfig.java   创建JobDetail或者Trigger时,调用usingJobData()设置数据
    读取数据   QuartzJob.java   执行任务时,调用 JobExecutionContext.getMergedJobDataMap() 获取数据

  1,设置数据:JobDetail和Trigger都可以调用usingJobData()方法设置数据。

  @Configuration
@ConfigurationProperties ( "quartz" )
public class  QuartzConfig {
      @Bean
      public  JobDetail  quartzJob () {
         JobDataMap dataMap =  new  JobDataMap() {{
             put( "job_str" ,  "str_test" ) ;
          }} ;

         return  JobBuilder. newJob (QuartzJob. class )
                 .usingJobData(dataMap)
                 .storeDurably()
                 .build() ;
      }

      @Bean
      public  Trigger  quartzTrigger () {
         CronScheduleBuilder scheduleBuilder = CronScheduleBuilder. cronSchedule ( cron ) ;
          JobDataMap dataMap =  new  JobDataMap() {{
             put( "trigger_int" ,  333 ) ;
          }} ;

         return  TriggerBuilder. newTrigger ()
                 .forJob(quartzJob())
                 .withSchedule(scheduleBuilder)
                 .usingJobData(dataMap)
                 .build() ;
      }

  }

  2,读取数据:从JobExecutionContext中读取JobDataMap获取数据,执行业务逻辑。

  public class  QuartzJob  extends  QuartzJobBean {
      @Override
      protected void  executeInternal (JobExecutionContext context)  throws  JobExecutionException {
          // get data from context
         JobDataMap dataMap = context.getMergedJobDataMap() ;
          for  (Map.Entry<String ,  Object> data : dataMap.entrySet()) {
             System. out .printf( "%s = %s
" ,  data.getKey() ,  data.getValue()) ;
         }

          // do work
     }
}

  3,运行输出:

  trigger_int =  333
job_str = str_test

               l   通过SchedulerContext传递数据

   另一个传递数据的方式是构建Scheduler时为SchedulerContext设置数据。 代码详见上文中第二、第三部分:

   代码下载:  https://github.com/jextop/StarterApi/

  src/main/java/com/starter/

  ├── controller/CheckController.java

  ├── job/QuartzJob.java

  读取数据方式一样,因为 JobExecutionContext.getMergedJobDataMap()已经将数据合并到一起。也可以通过调用SchedulerContext获取。

                     八,  Spring框架Schedule   功能   的使用方   法

  Spring Schedule支持异步执行定时任务,支持Cron表达式、固定间隔、固定频率三种配置方式,能满足小型项目对定时任务的功能需求。示例  代码:  https://github.com/rickding/HelloJava/tree/master/HelloQuartz

  src/main/java/com/hello/quartz/

  ├── QuartzApplication.java

  ├── ScheduledJob.java
    代码文件    功能  要点
   开启功能   QuartzApplication.java   SpringApplication增加注解:

  @EnableScheduling // 打开Schedule功能

  @EnableAsysnc // 异步方式执行定时任务
   配置任务   ScheduleJob.java   声明定时任务,功能注解:

  @Async // 异步方式执行,声明在类上面时,作用于类里面包含的任务

  @Scheduled // 声明定时任务执行时间

  @EnableAsync

      @EnableScheduling
@SpringBootApplication
public class  QuartzApplication {
      public static void  main (String[] args) {
         SpringApplication. run (QuartzApplication. class,  args) ;
      }
}

  1, cron表达式声明定时任务,比如每10秒执行一次:

      @Async
@Scheduled ( cron  =  "0/1 0  * * * *  " )
public void  scheduledCron () {
     System. out .printf( "scheduled cron: %s
" , new  Date()) ;
}

  2,  固定频率执行定时任务,比如每20秒执行一次:

  @Scheduled ( fixedRate  =  1000  *  2 0 ,  initialDelay  =  1000  *  2 0 )
public void  scheduledRate () {
     System. out .printf( "fixedRate: %s
" , new  Date()) ;
}

  3,  固定间隔执行定时任务,比如每20秒执行一次:

  @Scheduled ( fixedDelay  =  1000  *  3 0 ,  initialDelay  =  1000  *  3 0 )
public void  scheduledDelay () {
     System. out .printf( "fixedDelay: %s
" , new  Date()) ;
}

   注意固定频率和固定间隔两类定时任务,默认在程序启动时就会执行一次,可以通过指定initialDelay参数控制首次执行时间。

       scheduled cron: Sun Feb  09 18 : 09 : 19  CST  2020
      fixedRate: Sun Feb  09 18 : 09 : 28  CST  2020
      scheduled cron: Sun Feb  09 18 : 09 : 38  CST  2020

  --------------------------------

   点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小



----------------------------
原文链接:https://blog.51cto.com/13851865/2468550

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-03-13 12:11:40 重新编辑]
  Java面向对象编程-->按面向对象开发的基础范例
  JavaWeb开发-->访问数据库(Ⅱ)
  JSP与Hibernate开发-->立即检索和延迟检索策略
  Java网络编程-->Java网络编程入门
  精通Spring-->组合(Composition)API
  Vue3开发-->创建综合购物网站应用
  RocketMQ-Spring 为什么能成为 Spring 生态中最受欢迎的
  面试官:Mybatis里的设计模式有哪些?脱口而出8种
  Spring事务的声明和管理
  Spring 5 webflux响应式编程 - 但时间也偷换概念
  @Configuration注解的用法
  Spring MVC文件上传与下载
  Spring MVC实现国际化的几种方式
  SpringMVC 中 @ControllerAdvice 注解的三种使用场景!
  SSM三大框架整合详细教程
  Spring Cloud与Dubbo的完美融合之手「Spring Cloud Alibaba
  写给新手的Spring Cloud的微服务入门教程
  Kafka笔记整理
  Spring @Transactional注解失效解决方案
  Spring入门基础知识
  Hibernate拦截器与监听器
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。