入门简介:

基本上任何公司都会用到调度这个功能, 比如我们公司需要定期执行调度生成报表, 或者比如博客什么的定时更新之类的,都可以靠Quartz来完成。正如官网所说,小到独立应用大到大型电子商务网站, Quartz都能胜任。

Quartz体系结构:

明白Quartz怎么用,首先要了解Scheduler(调度器)、Job(任务)和Trigger(触发器)这3个核心的概念。

1. Job: 是一个接口,只定义一个方法execute(JobExecutionContext context),在实现接口的execute方法中编写所需要定时执行的Job(任务), JobExecutionContext类提供了调度应用的一些信息。Job运行时的信息保存在JobDataMap实例中;

2. JobDetail: Quartz每次调度Job时, 都重新创建一个Job实例, 所以它不直接接受一个Job的实例,相反它接收一个Job实现类(JobDetail:描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息),以便运行时通过newInstance()的反射机制实例化Job。

3. Trigger: 是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的15:00~16:00执行调度等;

Cron表达式的格式:秒 分 时 日 月 周 年(可选)。
字段名                 允许的值                        允许的特殊字符
秒                         0-59                               , – * /
分                         0-59                               , – * /
小时                   0-23                                 , – * /
日                         1-31                               , – * ? / L W C
月                         1-12 or JAN-DEC           , – * /
周几                     1-7 or SUN-SAT             , – * ? / L C #      MON  FRI
年 (可选字段)     empty, 1970-2099            , – * /

“?”字符:表示不确定的值
“,”字符:指定数个值
“-”字符:指定一个值的范围
“/”字符:指定一个值的增加幅度。n/m表示从n开始,每次增加m
“L”字符:用在日表示一个月中的最后一天,用在周表示该月最后一个星期X
“W”字符:指定离给定日期最近的工作日(周一到周五)
“#”字符:表示该月第几个周X。6#3表示该月第3个周五

Cron表达式范例:
每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
每周星期天凌晨1点实行一次:0 0 1 ? * L
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?

4. Calendar:org.quartz.Calendar和java.util.Calendar不同, 它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。 一个Trigger可以和多个Calendar关联, 以便排除或包含某些时间点。

假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。针对不同时间段类型,Quartz在org.quartz.impl.calendar包下提供了若干个Calendar的实现类,如AnnualCalendar、MonthlyCalendar、WeeklyCalendar分别针对每年、每月和每周进行定义;

5. Scheduler: 代表一个Quartz的独立运行容器, Trigger和JobDetail可以注册到Scheduler中, 两者在Scheduler中拥有各自的组及名称, 组及名称是Scheduler查找定位容器中某一对象的依据, Trigger的组及名称必须唯一, JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法, 允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

Scheduler可以将Trigger绑定到某一JobDetail中, 这样当Trigger触发时, 对应的Job就被执行。一个Job可以对应多个Trigger, 但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例;

6. ThreadPool: Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。
Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采用不同的执行方案。无状态任务在执行时拥有自己的JobDataMap拷贝,对JobDataMap的更改不会影响下次的执行。而有状态任务共享共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,也即每次执行任务后都会对后面的执行发生影响。
正因为这个原因,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,这意味着如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。有状态任务比无状态任务需要考虑更多的因素,程序往往拥有更高的复杂度,因此除非必要,应该尽量使用无状态的Job。
如果Quartz使用了数据库持久化任务调度信息,无状态的JobDataMap仅会在Scheduler注册任务时保持一次,而有状态任务对应的JobDataMap在每次执行任务后都会进行保存。
Trigger自身也可以拥有一个JobDataMap,其关联的Job可以通过JobExecutionContext#getTrigger().getJobDataMap()获取Trigger中的JobDataMap。不管是有状态还是无状态的任务,在任务执行期间对Trigger的JobDataMap所做的更改都不会进行持久,也即不会对下次的执行产生影响。

Quartz拥有完善的事件和监听体系,大部分组件都拥有事件,如任务执行前事件、任务执行后事件、触发器触发前事件、触发后事件、调度器开始事件、关闭事件等等,可以注册相应的监听器处理感兴趣的事件。

下图描述了Scheduler的内部组件结构,SchedulerContext提供Scheduler全局可见的上下文信息,每一个任务都对应一个JobDataMap,虚线表达的JobDataMap表示对应有状态的任务:

废话不多说, 上代码:

1. 最简单的Job代码(就打印Hello Quartz !):

1
2
3
4
5
6
7
8
9
10
11
12
packagecom.wenniuwuren.quartz; 
importorg.quartz.Job; 
importorg.quartz.JobExecutionContext; 
importorg.quartz.JobExecutionException; 
publicclassHelloQuartz  implementsJob { 
    publicvoidexecute(JobExecutionContext arg0) throwsJobExecutionException { 
        System.out.println("Hello Quartz !");                
    }        
}

2. 设置触发器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
packagecom.wenniuwuren.quartz; 
importorg.quartz.CronScheduleBuilder;   
importorg.quartz.JobBuilder;   
importorg.quartz.JobDetail;   
importorg.quartz.Scheduler;   
importorg.quartz.SchedulerException; 
importorg.quartz.SchedulerFactory;   
importorg.quartz.SimpleScheduleBuilder; 
importorg.quartz.Trigger;   
importorg.quartz.TriggerBuilder;   
importorg.quartz.impl.StdSchedulerFactory;   
publicclassSchedulerTest {   
   publicstaticvoid main(String[] args) throwsInterruptedException {   
       //通过schedulerFactory获取一个调度器   
       SchedulerFactory schedulerfactory = newStdSchedulerFactory();   
       Scheduler scheduler=null;   
       try{   
           // 通过schedulerFactory获取一个调度器   
           scheduler = schedulerfactory.getScheduler();   
            // 创建jobDetail实例,绑定Job实现类   
            // 指明job的名称,所在组的名称,以及绑定job类   
           JobDetail job = JobBuilder.newJob(HelloQuartz.class).withIdentity("JobName","JobGroupName").build();   
            // 定义调度触发规则   
            // SimpleTrigger  
//      Trigger trigger=TriggerBuilder.newTrigger().withIdentity("SimpleTrigger", "SimpleTriggerGroup")   
//                    .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3).withRepeatCount(6))   
//                    .startNow().build();   
            //  corn表达式  每五秒执行一次 
              Trigger trigger=TriggerBuilder.newTrigger().withIdentity("CronTrigger1","CronTriggerGroup")   
              .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))   
              .startNow().build();    
            // 把作业和触发器注册到任务调度中   
           scheduler.scheduleJob(job, trigger);   
           // 启动调度   
           scheduler.start();   
           Thread.sleep(10000); 
           // 停止调度 
           scheduler.shutdown(); 
       }catch(SchedulerException e){   
           e.printStackTrace();   
       }   
   }   
}

输出(设置了sleep10秒, 故在0秒调度一次, 5秒一次, 10秒最后一次):

from: http://www.importnew.com/22890.html

Quartz 入门详解相关推荐

  1. FFmpeg入门详解之82:FFmpeg转码器Java版之ava编码

    创建数据库:db_webavtc 创建数据表:avcategory(素材类别) id int primary key, pid int , cname varchar(255), cmemo varc ...

  2. linux 日志按大小切割_nginx入门详解(六)- 日志切割

    上一章讲解了nginx的目录加密功能,本章重点介绍nginx的日志切割. 笨办法学linux:nginx入门详解(五)- 目录加密​zhuanlan.zhihu.com 在第二章,我们探讨了nginx ...

  3. python怎么安装myqr模块-python二维码操作:对QRCode和MyQR入门详解

    python是所有编程语言中模块最丰富的 生活中常见的二维码功能在使用python第三方库来生成十分容易 三个大矩形是定位图案,用于标记二维码的大小.这三个定位图案有白边,通过这三个矩形就可以标识一个 ...

  4. python语言编程基础-Python语言入门详解!快速学成Python!

    原标题:Python语言入门详解!快速学成Python! 很多技能是被职场所需要的,但很可惜... 这些技能在大学中并学习不到. 大学和职场现实存在的横沟对大部分同学来说难以跨越或碰得头破血流... ...

  5. python语言入门m-Python语言入门详解!快速学成Python!

    今日主题 "Python语言入门详解" 近两年来,Python语言借着数据科学和人工智能的"东风"成为了最流行的编程语言--街头巷尾人们口口相传.同时,Pyth ...

  6. python语言入门详解-python初级教程:入门详解

    python初级教程:入门详解 Crifan Li 目录 前言 .................................................................... ...

  7. 【GCN】图卷积网络(GCN)入门详解

    机器学习算法与自然语言处理出品 @公众号原创专栏作者 Don.hub 单位 | 京东算法工程师 学校 | 帝国理工大学 图卷积网络(GCN)入门详解 什么是GCN GCN 概述 模型定义 数学推导 G ...

  8. python符号格式化设置区间_Python 数值区间处理_对interval 库的快速入门详解

    使用 Python 进行数据处理的时候,常常会遇到判断一个数是否在一个区间内的操作.我们可以使用 if else 进行判断,但是,既然使用了 Python,那我们当然是想找一下有没有现成的轮子可以用. ...

  9. 【JSON】JSON入门详解(二)

    文章目录 JSON基础文章荐读 JavaScript创建JSON对象 JSON与XML的那些事 JSON与XML的相同之处 JSON与XML的不同之处 AJAX相关JSON与XML JSON与XML的 ...

最新文章

  1. Java算法--插入排序算法
  2. HashMap 详解
  3. 2017-2018-2 20179317 《网络攻防技术》第七周学习心得体会
  4. 更新整理本人所有博文中提供的代码与工具(C++,2013.11)
  5. 系统缓存全解析 [转]
  6. PySide QtCore.Signal帮助手册
  7. Ruby gem 更换国内源
  8. IE重置input file
  9. SSM 实现学生成绩管理系统(完整代码)
  10. html的reset按钮的作用简单介绍
  11. Win12爆料,微软Windows 12计划3月份开始开发
  12. python繁简体转换
  13. MUI前端代码生成快捷键
  14. dbc批量插入、批量删除、批量更新
  15. 【读书笔记】Python编程:从入门到实践-埃里克·马瑟斯,python基础体系巩固和常见场景练习
  16. Swoole实现基于WebSocket的群聊私聊
  17. C#和WPF实现图形化编程
  18. jsp处理的生命周期
  19. MGRE结合OSPF
  20. 计算机游戏32,腾讯宣布将32款游戏退市 2019中国十大科技成就公布

热门文章

  1. keepalived程序包
  2. 数学建模学习笔记——层次分析法(评价类,专家打分一般不用)
  3. malloc与calloc的区别
  4. 一图看尽全生态, 2018区块链产业云图重磅发布
  5. 如何通过牛顿方法解决Logistic回归问题 By 机器之心2017年8月09日 16:30 本文介绍了牛顿方法(Newton's Method),以及如何用它来解决 logistic 回归。log
  6. 干货:2015年巴菲特六大投资建议
  7. 1930年的上海是什么样
  8. SpringBoot - 优雅的处理【长事务】
  9. python练习题实例_Python 练习实例65
  10. 哨兵机器人钢力士_哨兵胳膊都被卸了?巴西厂X战警钢力士正式公布