知识大全 Quartz调度框架应用总结
Posted 知
篇首语:一身转战三千里,一剑曾百万师。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Quartz调度框架应用总结相关的知识,希望对你有一定的参考价值。
Quartz调度框架应用总结 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
前一段时间项目需要做一个定时发送消息的功能 该功能依附于Web应用上 即当Web应用启动时 该应用就开始作用 起先决定使用java util Timer和java util TimerTask来实现 但是研究了一下以后发现Java Timer的功能比较弱 而且其线程的范围不受Web应用的约束 后来发现了Quartz这个开源的调度框架 非常有趣
首先我们要得到Quartz的最新发布版 目前其最新的版本是 我们可以从以下地址获得它的完整下载包 包中可谓汤料十足 不仅有我们要的quartz jar 更包含多个例程和详细的文档 从API到配置文件的XSD一应俱全 感兴趣的朋友也可以在src目录下找到该项目的源码一看究竟
废话少说 下面就来看一看这个东东是怎么在Java Web Application中得以使用的
首先不得不提出的是Quartz的三个核心概念 调度器 触发器 作业 让我们来看看他们是如何工作的吧 一.作业总指挥——调度器 .Scheduler接口 该接口或许是整个Quartz中最最上层的东西了 它提携了所有触发器和作业 使它们协调工作 每个Scheduler都存有JobDetail和Trigger的注册 一个Scheduler中可以注册多个JobDetail和多个Trigger 这些JobDetail和Trigger都可以通过group name和他们自身的name加以区分 以保持这些JobDetail和Trigger的实例在同一个Scheduler内不会冲突 所以 每个Scheduler中的JobDetail的组名是唯一的 本身的名字也是唯一的(就好像是一个JobDetail的ID) Trigger也是如此
Scheduler实例由SchedulerFactory产生 一旦Scheduler实例生成后 我们就可以通过生成它的工厂来找到该实例 获取它相关的属性 下面的代码为我们展示了如何从一个Servlet中找到SchedulerFactory并获得相应的Scheduler实例 通过该实例 我们可以获取当前作业中的testmode属性 来判断该作业是否工作于测试模式 view plaincopy to clipboardprint? //从当前Servlet上下文中查找StdSchedulerFactory
ServletContext ctx=request getSession() getServletContext();
StdSchedulerFactory factory = (StdSchedulerFactory) ctx getAttribute( quartz impl StdSchedulerFactory KEY );
Scheduler sch = null;
try
//获取调度器
sch = factory getScheduler( SchedulerName );
//通过调度器实例获得JobDetail 注意领会JobDetailName和GroupName的用法
JobDetail jd=sch getJobDetail( JobDetailName GroupName );
Map jobmap =jd getJobDataMap();
istest=jobmap get( testmode )+ ;
catch (Exception se)
//如果得不到当前作业 则从配置文件中读取testmode
ReadXML( job xml ) get( job testmode );
//从当前Servlet上下文中查找StdSchedulerFactory
ServletContext ctx=request getSession() getServletContext();
StdSchedulerFactory factory = (StdSchedulerFactory) ctx getAttribute( quartz impl StdSchedulerFactory KEY );
Scheduler sch = null;
try
//获取调度器
sch = factory getScheduler( SchedulerName );
//通过调度器实例获得JobDetail 注意领会JobDetailName和GroupName的用法
JobDetail jd=sch getJobDetail( JobDetailName GroupName );
Map jobmap =jd getJobDataMap();
istest=jobmap get( testmode )+ ;
catch (Exception se)
//如果得不到当前作业 则从配置文件中读取testmode
ReadXML( job xml ) get( job testmode );
Scheduler实例生成后 它处于 stand by 模式 需要调用其start方法来使之投入运作 view plaincopy to clipboardprint? public class SendMailShedule
//设置标准SchedulerFactory
static SchedulerFactory schedFact = new quartz impl StdSchedulerFactory();
static Scheduler sched;
public static void run()throws Exception
//生成Scheduler实例
sched = schedFact getScheduler();
//创建一个JobDetail实例 对应的Job实现类是SendMailJob
JobDetail jobDetail = new JobDetail( myJob sched DEFAULT_GROUP SendMailJob class);
//设置CronTrigger 利用Cron表达式设定触发时间
CronTrigger trigger = new CronTrigger( myTrigger test * ? );
sched scheduleJob(jobDetail trigger);
sched start();
public static void stop()throws Exception
sched shutdown();
public class SendMailShedule
//设置标准SchedulerFactory
static SchedulerFactory schedFact = new quartz impl StdSchedulerFactory();
static Scheduler sched;
public static void run()throws Exception
//生成Scheduler实例
sched = schedFact getScheduler();
//创建一个JobDetail实例 对应的Job实现类是SendMailJob
JobDetail jobDetail = new JobDetail( myJob sched DEFAULT_GROUP SendMailJob class);
//设置CronTrigger 利用Cron表达式设定触发时间
CronTrigger trigger = new CronTrigger( myTrigger test * ? );
sched scheduleJob(jobDetail trigger);
sched start();
public static void stop()throws Exception
sched shutdown();
另外 我们也可以通过监听器来跟踪作业和触发器的工作状态
二.作业及其相关
. Job
作业实际上是一个接口 任何一个作业都可以写成一个实现该接口的类 并实现其中的execute()方法 来完成具体的作业任务
. JobDetail
JobDetail可以指定我们作业的详细信息 比如可以通过反射机制动态的加载某个作业的实例 可以指定某个作业在单个调度器内的作业组名称和具体的作业名称 可以指定具体的触发器
一个作业实例可以对应多个触发器(也就是说学校每天 点放一次眼保健操录音 下午 点半可以再放一次) 但是一个触发器只能对应一个作业实例( 点钟的时候学校不可能同时播放眼保健操和广播体操的录音)
. JobDataMap
这是一个给作业提供数据支持的数据结构 使用方法和java util Map一样 非常方便 当一个作业被分配给调度器时 JobDataMap实例就随之生成
Job有一个StatefulJob子接口 代表有状态的任务 该接口是一个没有方法的标签接口 其目的是让Quartz知道任务的类型 以便采用不同的执行方案 无状态任务在执行时拥有自己的JobDataMap拷贝 对JobDataMap的更改不会影响下次的执行 而有状态任务共享共享同一个JobDataMap实例 每次任务执行对JobDataMap所做的更改会保存下来 后面的执行可以看到这个更改 也即每次执行任务后都会对后面的执行发生影响
正因为这个原因 无状态的Job可以并发执行 而有状态的StatefulJob不能并发执行 这意味着如果前次的StatefulJob还没有执行完毕 下一次的任务将阻塞等待 直到前次任务执行完毕 有状态任务比无状态任务需要考虑更多的因素 程序往往拥有更高的复杂度 因此除非必要 应该尽量使用无状态的Job
如果Quartz使用了数据库持久化任务调度信息 无状态的JobDataMap仅会在Scheduler注册任务时保持一次 而有状态任务对应的JobDataMap在每次执行任务后都会进行保存
JobDataMap实例也可以与一个触发器相关联 这种情况下 对于同一作业的不同触发器 我们可以在JobDataMap中添加不同的数据 以便作业在不同时间执行时能够提供更为灵活的数据支持(学校上午放眼保健操录音第一版 下午放第二版)
不管是有状态还是无状态的任务 在任务执行期间对Trigger的JobDataMap所做的更改都不会进行持久 也即不会对下次的执行产生影响
三.触发器
Trigger是一个抽象类 它有三个子类 SimpleTrigger CronTrigger和NthIncludedDayTrigger 前两个比较常用
SimpleTrigger 这是一个非常简单的类 我们可以定义作业的触发时间 并选择性的设定重复间隔和重复次数
CronTrigger 这个触发器的功能比较强大 而且非常灵活 但是你需要掌握有关Cron表达式的知识 如果你是一个Unix系统爱好者 你很可能已经具备这种知识 但是如果你不了解Cron表达式 请看下面的Cron详解
Cron表达式由 或 个由空格分隔的时间字段组成 如表 所示
表 Cron表达式时间字段
位置
时间域名
允许值
允许的特殊字符
秒
* /
分钟
* /
小时
* /
日期
* ? / L W C
月份
* /
星期
* ? / L C #
年(可选)
空值
* /
Cron表达式的时间字段除允许设置数值外 还可使用一些特殊的字符 提供列表 范围 通配符等功能 细说如下
●星号(*) 可用在所有字段中 表示对应时间域的每一个时刻 例如 *在分钟字段时 表示 每分钟
●问号(?) 该字符只在日期和星期字段中使用 它通常指定为 无意义的值 相当于点位符
●减号( ) 表达一个范围 如在小时字段中使用 则表示从 到 点 即
●逗号( ) 表达一个列表值 如在星期字段中使用 MON WED FRI 则表示星期一 星期三和星期五
●斜杠(/) x/y表达一个等步长序列 x为起始值 y为增量步长值 如在分钟字段中使用 / 则表示为 和 秒 而 / 在分钟字段中表示 你也可以使用*/y 它等同于 /y
●L 该字符只在日期和星期字段中使用 代表 Last 的意思 但它在两个字段中意思不同 L在日期字段中 表示这个月份的最后一天 如一月的 号 非闰年二月的 号 如果L用在星期中 则表示星期六 等同于 但是 如果L出现在星期字段里 而且在前面有一个数值X 则表示 这个月的最后X天 例如 L表示该月的最后星期五
●W 该字符只能出现在日期字段里 是对前导日期的修饰 表示离该日期最近的工作日 例如 W表示离该月 号最近的工作日 如果该月 号是星期六 则匹配 号星期五 如果 日是星期日 则匹配 号星期一 如果 号是星期二 那结果就是 号星期二 但必须注意关联的匹配日期不能够跨月 如你指定 W 如果 号是星期六 结果匹配的是 号星期一 而非上个月最后的那天 W字符串只能指定单一日期 而不能指定日期范围
●LW组合 在日期字段可以组合使用LW 它的意思是当月的最后一个工作日
●井号(#) 该字符只能在星期字段中使用 表示当月某个工作日 如 # 表示当月的第三个星期五( 表示星期五 # 表示当前的第三个) 而 # 表示当月的第五个星期三 假设当月没有第五个星期三 忽略不触发
● C 该字符只在日期和星期字段中使用 代表 Calendar 的意思 它的意思是计划所关联的日期 如果日期没有被关联 则相当于日历中所有日期 例如 C在日期字段中就相当于日历 日以后的第一天 C在星期字段中相当于星期日后的第一天 Cron表达式对特殊字符的大小写不敏感 对代表星期的缩写英文大小写也不敏感 表 下面给出一些完整的Cron表示式的实例
表 Cron表示式示例
表示式
说明
* * ?
每天 点运行
? * *
每天 : 运行
* * ?
每天 : 运行
* * ? *
每天 : 运行
* * ?
在 年的每天 运行
* * * ?
每天 点到 点之间每分钟运行一次 开始于 : 结束于 :
/ * * ?
每天 点到 点每 分钟运行一次 开始于 : 结束于 :
/ * * ?
每天 点到 点每 分钟运行一次 此外每天 点到 点每 钟也运行一次
* * ?
每天 : 点到 : 每分钟运行一次
? WED
月每周三的 : 分到 : 每分钟运行一次
? * MON FRI
每周一 二 三 四 五的 : 分运行
* ?
每月 日 : 分运行
L * ?
每月最后一天 : 分运行
? * L
每月最后一个星期五 : 分运行
? * L
在 年每个月的最后一个星期五的 : 分运行
? * #
每月第三个星期五的 : 分运行
好 说了这么多 最后让我们来看看如何在Web应用中使用Quartz 由于Scheduler的配置相当的个性化 所以 在Web应用中 我们可以通过一个quartz properties文件来配置QuartzServlet 不过之前让我们先来看看web xml中如何配置 web xml view plaincopy to clipboardprint? <servlet> <servlet name> QuartzInitializer </servlet name> <display name> Quartz Initializer Servlet </display name> <servlet class> quartz ee servlet QuartzInitializerServlet </servlet class> <load on startup> </load on startup> <init param> <param name>config file</param name> <param value>/quartz properties</param value> </init param> <init param> <param name>shutdown on unload</param name> <param value>true</param value> </init param> <init param> <param name>start scheduler on load</param name> <param value>true</param value> </init param> </servlet> <servlet> <servlet name> QuartzInitializer </servlet name> <display name> Quartz Initializer Servlet </display name> <servlet class> quartz ee servlet QuartzInitializerServlet </servlet class> <load on startup> </load on startup> <init param> <param name>config file</param name> <param value>/quartz properties</param value> </init param> <init param> <param name>shutdown on unload</param name> <param value>true</param value> </init param> <init param> <param name>start scheduler on load</param name> <param value>true</param value> </init param> </servlet> 这里 load on startup是指定QuartzServlet是否随应用启动 表示否 正数表示随应用启动 数值越小 则优先权越高 初始化参数中 config file里面可以指定QuartzServlet的配置文件 这里我们用的是quartz properties shutdown on unload 表示是否在卸载应用时同时停止调度 该参数推荐true 否则你的tomcat进程可能停不下来 start scheduler on load 表示应用加载时就启动调度器 如果为false 则quartz properties中指定的调度器在用户访问这个Servlet之后才会加载 在此之前 如果你通过ServletContext查找SchedulerFactory是可以找到的 但是要得到具体的Scheduler 那么你一定会发现Jvm抛出了一个NullPointerExcetion 下面就来看看quartz properties的真面目 quartz properties view plaincopy to clipboardprint? quartz scheduler instanceName = PushDBScheduler quartz scheduler instanceId = one quartz threadPool class = quartz simpl SimpleThreadPool quartz threadPool threadCount = quartz threadPool threadPriority = quartz plugin jobInitializer class = quartz plugins xml JobInitializationPlugin quartz plugin jobInitializer fileName = quartz_job xml quartz scheduler instanceName = PushDBScheduler quartz scheduler instanceId = one quartz threadPool class = quartz simpl SimpleThreadPool quartz threadPool threadCount = quartz threadPool threadPriority = quartz plugin jobInitializer class = quartz plugins xml JobInitializationPlugin quartz plugin jobInitializer fileName = quartz_job xml 我想不用多说 大家都看出来了 首先配置了基本的Scheduler实例名 并分配了ID 然后为这个调度器设定了线程池 后面是初始化插件 初始化插件是Quartz非常实用的功能 你可以用这个功能来实现Quartz的扩展性 这里配置的插件是读取job XML文件 让调度器自动载入Job 这个插件现在支持读取多个job XML文件 但是我现在还没有试过 感兴趣的读者可以自己尝试 另外就是有一个scanInterval属性 表示每隔几秒自动扫描一次job XML文件 我现在也没有试过 感兴趣的读者可以自己试验一下 注意 该参数设定为 表示不扫描 最后 我们来看看job XML文件 这里以quartz_job xml为例 quartz_job xml view plaincopy to clipboardprint? <quartz> <job> <job detail> <name>ScanItemsInDB</name> <group>Scanning</group> <job class> testquartz ScanDB</job class> <job data map allows transient data= true > <entry> <key>testmode</key> <value>true</value> </entry> </job data map> </job detail> <trigger> <cron> <name>t </name> <group> Scanning </group> <job name> ScanItemsInDB </job name> <job group> Scanning </job group> <cron expression> / * * * ?</cron expression> </cron> </trigger> </job> </quartz> <quartz> <job> <job detail> <name>ScanItemsInDB</name> <group>Scanning</group> <job class> testquartz ScanDB</job class> <job data map allows transient data= true > <entry> <key>testmode</key> <value>true</value> </entry> </job data map> </job detail> <trigger> <cron> <name>t </name> <group> Scanning </group> <job name> ScanItemsInDB </job name> <job group> Scanning </job group> <cron expression> / * * * ?</cron expression> </cron> </trigger> </job> </quartz> 这个文件真是非常显而易见了 我就不多说了 大家自己研究吧 然后你只要自己写一下ScanDB这个类就可以了 ScanDB java view plaincopy to clipboardprint? public class ScanDB implements Job public void execute(JobExecutionContext context) throws JobExecutionException //你的代码 public class ScanDB implements Job public void execute(JobExecutionContext context) throws JobExecutionException //你的代码 注意JobExecutionContext这个类 这个类是用来存取任务执行时的相关信息的 从中我们可以获取当前作业的Trigger Scheduler JobDataMap等等 当然 Scheduler也有对应的SchedulerContext 具体的用途很像ServletContext 有兴趣的读者自己研究吧 另外就是可以提供一个提示 在一个作业执行的时候 你就可以设定另外一个调度器 去执行另一个Job 这样你可以每个一段时间扫描一下数据库 然后看一看数据库里有没有下一个时间段待发的邮件 然后调用一个新的调度器实例 以便在指定的发送时间将其发送出去 cha138/Article/program/Java/hx/201311/26569相关参考
知识大全 Timer,Quartz和Spring实现作业调度
Timer,Quartz和Spring实现作业调度 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
Java调度任务和SpringQuartz 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 并非所
知识大全 Winform开发框架之权限管理系统改进的经验总结(2)-用户选择界面的设计
Winform开发框架之权限管理系统改进的经验总结(2)-用户选择界面的设计 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让
知识大全 我是一名高中生,数学成绩一直下滑,想总结基础知识框架。不知如何下手。要详细一点
我是一名高中生,数学成绩一直下滑,想总结基础知识框架。不知如何下手。要详细一点高中数学跟初中联系很小,即是初成绩不好也没关系,而同学说话的意思是以前成绩不错,这就更没必要但心了。高中数学就是代数几何结
Spring中Quartz的配置 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Quartz是一
详细讲解Quartz如何从入门到精通 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Quartz
烟晶是有浅黄到烟棕色的,甚至几乎是黑色的粗晶质的石英变种。它最早是在苏格兰的凯戈姆山,因此又叫凯戈姆石。
Spring整合Quartz定时发送邮件 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 功能描述
石英是一种二氧化硅矿物,它很丰富,分布也广,它在很多火成岩、变质岩和沉积岩中是作为一种重要成份存在的。它在砂岩和石英岩以及未固结的砂子及砾石中是主要矿物。石英的完好晶体比其他任何矿物容易找到得多。在矿
Spring集成Quartz的XML配置 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! <