quartz怎么开始和关闭python定时任务框架

博客分类:
最近在研究Spring中的定时任务功能,最好的办法当然是使用Quartz来实现。对于一个新手来说,花了我不少时间,这里我写个笔记,给大家参考。
我使用的是Maven来管理项目,需要的Jar包我给大家贴出来。
quartz-1.8.5.jar
commons-logging.jar
spring-core-3.0.5.RELEASE.jar
spring-beans-3.0.5.RELEASE.jar
spring-context-3.0.5.RELEASE.jar
spring-context-support-3.0.5.RELEASE.jar
spring-asm-3.0.5.RELEASE.jar
spring-expression-3.0.5.RELEASE.jar
spring.transaction-3.0.5.RELEASE.jar
spring-web-3.0.5.RELEASE.jar
Maven的pom.xml的配置:
&?xml version="1.0" encoding="UTF-8"?&
&project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&modelVersion&4.0.0&/modelVersion&
&groupId&QtzTest&/groupId&
&artifactId&QtzTest&/artifactId&
&version&1.0&/version&
&properties&
&springframework.version&3.0.5.RELEASE&/springframework.version&
&/properties&
&dependencies&
&dependency&
&groupId&org.springframework&/groupId&
&artifactId&spring-context&/artifactId&
&version&${springframework.version}&/version&
&/dependency&
&dependency&
&groupId&org.springframework&/groupId&
&artifactId&spring-context-support&/artifactId&
&version&${springframework.version}&/version&
&/dependency&
&dependency&
&groupId&org.springframework&/groupId&
&artifactId&spring-tx&/artifactId&
&version&${springframework.version}&/version&
&/dependency&
&dependency&
&groupId&org.springframework&/groupId&
&artifactId&spring-web&/artifactId&
&version&${springframework.version}&/version&
&/dependency&
&dependency&
&groupId&org.quartz-scheduler&/groupId&
&artifactId&quartz&/artifactId&
&version&1.8.5&/version&
&/dependency&
&/dependencies&
&finalName&${project.artifactId}&/finalName&
&groupId&org.mortbay.jetty&/groupId&
&artifactId&jetty-maven-plugin&/artifactId&
&version&7.5.4.v&/version&
&configuration&
&scanIntervalSeconds&10&/scanIntervalSeconds&
&contextPath&/${project.artifactId}&/contextPath&
&/configuration&
&/plugins&
&/project&
特别注意一点,与Spring3.1以下版本整合必须使用Quartz1,最初我拿2.1.3的,怎么搞都报错:
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.scheduling.quartz.CronTriggerBean] for bean with name 'mytrigger' defined in class path resource [applicationContext.xml]: problem with class fil nested exception is java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class
查看发现spring3.0.5中org.springframework.scheduling.quartz.CronTriggerBean继承了org.quartz.CronTrigger(public class CronTriggerBeanextends CronTrigger),而在quartz2.1.3中org.quartz.CronTrigger是个接口(publicabstract interface CronTrigger extends Trigger),而在quartz1.8.5及1.8.4中org.quartz.CronTrigger是个类(publicclass CronTrigger extends Trigger),从而造成无法在applicationContext中配置触发器。这是spring3.1以下版本和quartz2版本不兼容的一个bug。(感谢tiren的回复,spring3.1以及以后版本支持quartz2)
在Spring中使用Quartz有两种方式实现:第一种是任务类继承QuartzJobBean,第二种则是在配置文件里定义任务类和要执行的方法,类和方法仍然是普通类。很显然,第二种方式远比第一种方式来的灵活。
第一种方式的JAVA代码:
package com.ncs.
import org.quartz.JobExecutionC
import org.quartz.JobExecutionE
import org.springframework.scheduling.quartz.QuartzJobB
public class SpringQtz extends QuartzJobBean{
private static int counter = 0;
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println();
long ms = System.currentTimeMillis();
System.out.println("\t\t" + new Date(ms));
System.out.println(ms);
System.out.println("(" + counter++ + ")");
String s = (String) context.getMergedJobDataMap().get("service");
System.out.println(s);
System.out.println();
第二种方式的JAVA代码:
package com.ncs.
import org.quartz.JobExecutionC
import org.quartz.JobExecutionE
import org.springframework.scheduling.quartz.QuartzJobB
import java.util.D
public class SpringQtz {
private static int counter = 0;
protected void execute()
long ms = System.currentTimeMillis();
System.out.println("\t\t" + new Date(ms));
System.out.println("(" + counter++ + ")");
Spring的配置文件:
&!------------ 配置调度程序quartz ,其中配置JobDetail有两种方式--------------&
&!--方式一:使用JobDetailBean,任务类必须实现Job接口 --&
&bean id="myjob" class="org.springframework.scheduling.quartz.JobDetailBean"&
&property name="name" value="exampleJob"&&/property&
&property name="jobClass" value="com.ncs.hj.SpringQtz"&&/property&
&property name="jobDataAsMap"&
&entry key="service"&&value&simple is the beat&/value&&/entry&
&/property&
&!--运行时请将方式一注释掉! --&
&!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法--&
&!-- 定义目标bean和bean中的方法 --&
&bean id="SpringQtzJob" class="com.ncs.hj.SpringQtz"/&
&bean id="SpringQtzJobMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"&
&property name="targetObject"&
&ref bean="SpringQtzJob"/&
&/property&
&property name="targetMethod"&
&!-- 要执行的方法名称 --&
&value&execute&/value&
&/property&
&!-- ======================== 调度触发器 ======================== --&
&bean id="CronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean"&
&property name="jobDetail" ref="SpringQtzJobMethod"&&/property&
&property name="cronExpression" value="0/5 * * * * ?"&&/property&
&!-- ======================== 调度工厂 ======================== --&
&bean id="SpringJobSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"&
&property name="triggers"&
&ref bean="CronTriggerBean"/&
&/property&
关于cronExpression表达式,这里讲解一下:
字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空,
, - * /
表达式意义
"0 0 12 * * ?" 每天中午12点触发
"0 15 10 ? * *" 每天上午10:15触发
"0 15 10 * * ?" 每天上午10:15触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 年的每天上午10:15触发
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
"0 15 10 15 * ?" 每月15日上午10:15触发
"0 15 10 L * ?" 每月最后一日的上午10:15触发
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6L " 2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
每天早上6点
0 6 * * *
每两个小时
0 */2 * * *
晚上11点到早上8点之间每两个小时,早上八点
0 23-7/2,8 * * *
每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点
0 11 4 * 1-3
1月1日早上4点
0 4 1 1 *
最后别忘了在web.xml里面配置Spring:
&?xml version="1.0" encoding="UTF-8"?&
&web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"&
&welcome-file-list&
&welcome-file&index.html&/welcome-file&
&/welcome-file-list&
&context-param&
&param-name&contextConfigLocation&/param-name&
&param-value&/WEB-INF/spring-config.xml&/param-value&
&/context-param&
&listener&
&listener-class&org.springframework.web.context.ContextLoaderListener&/listener-class&
&/listener&
&/web-app&
运行结果:
Wed Feb 08 13:58:30 CST 2012
(0)
Wed Feb 08 13:58:35 CST 2012
(1)
Wed Feb 08 13:58:40 CST 2012
(2)
Wed Feb 08 13:58:45 CST 2012
(3)
Wed Feb 08 13:58:50 CST 2012
(4)
Wed Feb 08 13:58:55 CST 2012
(5)
Wed Feb 08 13:59:00 CST 2012
(6)
浏览 261048
[/list][/img][/url][/flash][/b][/b][/b][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]
楼主,我项目中也用spring+quartz来作定时任务调度的。。。我设置的定时器表达式是:0 0/10 1-12 * * ?因为我有个程序跑,需要另外一个系统给我数据,但是这个系统数据返回的时间不确定。。。所以我设置这么个定时任务,在每天凌晨1点到12点,每隔10分钟轮训一次。。。。现在的问题是:我发现如果我再2点10分轮询到数据返回后,我启动我执行任务。。。但是我2点20分我的定时又会调度一次。。。。这种有什么好的办法解决?applicationContext.xml中jobDetail bean添加如下配置,应该就可以了&!--将并发设置为false--&& &&& &property name="concurrent" value="false" /&& 试试,应该能解决你的问题
& 上一页 1
浏览: 365756 次
来自: 南京
除了中文发音还能有其他语言吗?
[i][i][i][i][i][i][i][i][i][i][ ...
晚上11点到早上8点之间每两个小时,早上八点 0 23-7/2 ...
非常感谢楼主!你的项目如果是spring2,使用quartz- ...
不知道为什么。
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'quartz【直线的秘密吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:11贴子:
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 1.8.0。
定时器(Quartz)使用说明&
本文目前主要包括如下几个部分:&
Quartz功能简介&:介绍Quartz的特点及概念。&
使用Quartz的常见问题&:很多用户在使用过程中遇到常见问题的解答。&
快速开始:让读者尽快掌握Quartz开发。&
:通过一些列的课程来指导如何使用Quartz.&
Quartz功能简介&
Quartz特点:&
..&Quartz能嵌入到任何独立的应用中运行。&
..&Quartz能在应用服务器或者Servlet容器中实例化,并且能够参与XA事务。&
..&Quartz能够以独立的方式运行(在它自己的Java虚拟机中),可以通过RMI使用
Quartz。&
..&Quartz可以被实例化为独立程序的集群(有负载均衡和容错能力)。&
Job&Scheduling(任务日程安排)&
任务在给定的触发器(Trigger)触发时执行。触发器可以通过几乎以下所有形式的组
合方式进行创建:&
..&在一天中的任意时刻(可以精确到毫秒)。&
..&一周中特定的一些天。&
..&一个月中特定的一些天。&
..&一年中特定的一些天&
..&不在日历列表中注册的一些天(比如节假日)。&
..&循环特定的次数。&
..&循环到特定的时间。&
..&无限循环。&
..&按照一定的时间间隔循环。&
“任务”由创建者给定名字,并且可以加入到给定名称的“任务组”中。为了简化触
发器在日程中的管理,“触发器”也可以被给定名字和分组。任务只能加入到日程中一次,
但是可以为其注册多个触发器。在J2EE环境中,任务可以作为分布(XA)事务的一部分执
行。&
Job&Execution(任务执行)&
.&任务是任何实现简单Job接口的Java&类,这样开发者能够执行任何完成他们工作
的任务。&
.&任务类的实例可以由Quartz实例化,也可以由你的程序框架实例化。&
当触发器被触发时,日程管理器将会通知某个或者多个实现了JobListener&或&
TriggerListener的对象(监听器可以是简单的Java对象,或者EJBs,或者JMS消息
发布器,等等)。这些监听器在任务执行完毕后也会接到通知。&
.&任务被完成后,他们会返回一个“任务完成码(JobCompletionCode)”,这个
“任务完成码”告知日程管理器任务执行的结果是成功还是失败。日程管理器会根
据成功或者失败码来采取措施,比如:立即重新执行任务。&
Job&Persistence(任务持久化)&
.&Quartz设计中包括了一个JobStore接口,这样,实现这个接口的Job类可以以
多种机制实现Job的存储。&
.&通过使用JDBCJobStore,所有的Jobs和Triggers被配置为“non-volatile”(不
轻快)的方式。即,通过JDBC存储在关系数据库中。&
.&通过使用RAMJobStore,所有Jobs和Triggers被存储在RAM。因此,在程序
执行中没有被持久化,但这种方式的优点就是不需要外部数据库。&
Transactions(事务)&
.&Quartz通过JobStoreCMT(JDBCJobStore的一个子类)可参与JTA事务。&
.&Quartz可以管理JTA事务(开始或者提交事务)。&
Clustering(集群)&
.&Fail-over.(容错)&
.&Load&balancing.(负载均衡)&
Listeners&&&Plug-Ins(监听器及插件)&
.&应用可以通过实现一个或者多个监听器接口来实现捕捉日程事件,以监视或控制任
务/触发器的行为。&
.&可以通过插件的机制来扩展Quartz&的功能。例如:记录任务执行历史的日志,或
者从文件中载入任务和触发器的定义。&
.&Quartz自带了一些“factory&built(内建)”的插件和监听器。&
.&Quartz是什么?&
.&为什么不使用java.util.Timer?&
.&如何build&Quartz源码?&
.&Quartz可以运行多少任务?&
.&通过RMI使用Quartz存在一些问题。&
关于Jobs的问题&
.&如何能够控制Jobs的实例化。&
.&如何避免一个任务在完成后被移(删)除?&
.&如何避免一个Job被并发激活?&
.&如何停止一个正在执行的任务?&
关于触发器的问题:&
.&如何串行任务的执行?或者,如何能够创建一个工作流程?&
.&为什么触发器没有被触发?&
.&夏令时和触发器&
关于JDBCJobStore的问题&
.&如何提高JDBC-JobStore的性能?&
.&如果数据服务器重新启动,DB连接不能够正确恢复&
关于事务的问题&
.&使用JobStoreCMT并且发现了死锁,该如何做?&
General&Questions&一般问题&
Quartz是什么?&
Quartz是一个任务日程管理系统,这个系统可以与任何其他软件系统集成或者一起
使用。术语“日程进度管理器”可能对于不同的人有不同的理解。当你阅读这个指南之后,
你会对这个术语有固定的理解。简而言之,“任务进度管理器”就是一个在预先确定(被
纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。&
为了达到预想目的,或者是能够写出与工程最“自然”衔接的软件代码,Quartz相
地灵活,并且包括了多个用法范例,可以单独运用这些范例或者组合运用这些范例。&
Quartz相当“轻量”,并且需要非常少的步骤/配置,如果需求比较基本,Quartz
确实非常容易使用。&
Quartz具有容错性,并且可以在你系统重起的时候持久化(记住)被纳入日程的任
务。&
虽然Quartz对于按照简单地给定日程运行的系统时非常有用,但是,当你学会如何
使用它来驱动你应用中的商务过程,那么你才会认识到它的全部潜能。&
从软件组件的角度来看,Quartz是什么?&
Quartz用一个小Java库发布文件(.jar文件),这个库文件包含了所有Quartz核
心功能。这些功能的主要接口(API)是Scheduler接口。它提供了简单的操作,例如:将
任务纳入日程或者从日程中取消,开始/停止/暂停日程进度。&
如果你想将软件组件的执行纳入到日程中,它们只需简单地实现Job接口,这个接口
有一个execute()方法。如果希望在日程安排的时间到达时通知组件,那么这些组件应实
现TriggerListener或者JobListener接口。&
Quartz主过程可以在应用中启动或者运行,也可以作为一个独立的应用(带有RMI
接口),或者在一个J2EE&应用服务器中运行,并且可作为其它J2EE组件的一种引用资
源。&
&为什么不使用java.util.Timer?&
从JDK1.3开始,Java有了内建的定时器功能,即,通过java.util.Timer和
java.util.TimerTask来实现,为什么有人用Quartz而不用这些标准特性呢?有很多原
因,下面是其中的一些:&
1.&Java定时器没有持久化机制。&
2.&Java定时器的日程管理不够灵活(只能设置开始时间、重复的间隔,设置特定的日
期、时间等)&
3.&Java定时器没有使用线程池(每个Java定时器使用一个线程)&
4.&Java定时器没有切实的管理方案,你不得不自己完成存储、组织、恢复任务的措施。&
...当然,对于某些简单的应用来说,这些特性可能不那么重要,在这种情况下,不使用
Quartz也是正确的选择。&
如何build&Quartz源码?&
尽管Quartz以“预先编译”的形式打包。很多人可能想做他们自己的改变或者buil
从CVS上得到的最新的“未发布”的Quartz版本。阅读随同Quartz一起打包的
&README.TXT&文件就知道怎么做。&
Miscellaneous&Questions&杂项问题&
Quartz可以运行多少任务?&
这是一个比较难以回答的问题,答案基本上是“看它依赖于什么环境”。&
你可能不喜欢这个答案,这里有一些关于它所依赖环境的信息。&
首先,JobStore对性能有重要的影响.基于RAM的JobStore要比基于JDBC的
JobStore快的多。基于JDBC的JobStore的速度几乎完全取决于对数据库连接的速度,
以及使用的数据系统以及数据库运行的硬件。Quartz本身实际上只做很少的处理,差不
多所有的时间都花费在数据库上。当然,RAMJobStore对于有多少“任务”或者“触发
器”可以存储是有数量限制的,因为,内存的数量要比数据库的硬盘空间小的多。你可以
参考问题“如何提高JDBC-JobStore的性能?”。&
因此,对于Quartz能存储和监控的触发器和任务的数量限制因素时间上是JobStore
有多少可用的存储空间的数量。(内存数量或者是硬盘数量)。&
现在,除了“能存储多少?”的问题之外,就是“Quartz能同时运行多少个任务?”&
能够使Quartz本身运行变慢的就是使用大量的监听器(TriggerListeners,&
JobListeners,&和&SchedulerListeners),除了任务本身实际的运行时间外,花费在每
个监听器上的时间会直接记入“处理”任务的执行时间上。这不意味着因此而害怕使用监
听器,而是说要明智地使用监听器。如果能够使用特定的监听器就不要创建大量“全局”
监听器,也不要使用监听器作“耗时”的工作,除非必须做。另外,也要留心,很多插件
实际上也是监听器(例如:“history”插件)。&
同时能够运行多少个任务受限于线程池的大小。如果池中有5个线程,则同时可运行
的任务不超过5个。使用大量线程时要小心,因为JVM,操作系统和CPU处理大量线程时
很耗时,并且,线程管理也会导致性能下降。在多数情况下,性能开始下降是因为使用多
达数百个线程。如果在应用服务器中运行程序,要留心应用服务器本身已经创建了不少的
线程。&
除了这些因素外,还同要执行的任务有关,如果任务需要花费很长时间才能完成它们
的工作,并且(或者)它们的工作很消耗CPU,那么很明显不要同时运行多个任务,也不
要在一个时间段内运行过多这样的任务。&
最后,如果不能通过一个Quartz实例获得足够的性能,你可以将多个Quartz实例
(放在不同的机器上)进行负载均衡。每个Quartz都按照“先到先服务”的原则在共享
的数据库之外运行任务。&
目前为止,你已经知道有关“多少个”的答案很多知识,而且还是没有给出一个具体
的数量,并且由于以上提及的各种因素,我也不愿意给出。因此,只是说,很多地方使用
Quartz管理成百上千的任务和触发器,并且在任何给定的时刻,都有很多任务在执行,
并且这些不包括负载均衡。有了这个印象,很多人都会对使用Quartz充满信心。&
通过RMI使用Quartz存在一些问题。&
RMI可能会有一些小的问题,尤其当你不理解RMI如何加载类的时候。强烈推荐阅
读所有关RMI的JavaDOC,并且强烈建议阅读一下参考文档,这些参考资料由一个好心
的Quartz用户整理(Mike&Curwen)。&
关于RMI的出色的描述和codebase:&
其中的一个重点就是了解用于客户
端的”codebase”。&
有关安全管理的快讯:&
&
来自于Java&API&文档,阅读关于RMISecurityManager&的文档
API中需要重点掌握的就是:&
如果没有安全管理器的设置,RMI的类加载器不会从远程位置下载任何类。&
Questions&About&Jobs&
如何能够控制Jobs的实例化?&
看有关org.quartz.spi.JobFactory和org.quartz.Scheduler.setJobFactory()
方法的说明。&
如何避免一个任务在完成后被移(删)除?&
设置属性JobDetail.setDurability(true),这将指示Quartz在任务变为“孤儿”(当
任务不在被任何触发器所引用时)时不要删除任务。&
如何避免一个Job被并发激活?&
使Job类实现StatefulJob接口,而不是Job接口。阅读JavaDOC获得有关
StatefulJob接口的更多信息。&
如何停止一个正在执行的任务?&
参见org.quartz.InterruptableJob接口和Scheduler.interrupt(String,&String)
方法。
Questions&About&Triggers&
如何串行任务的执行?或者,如何能够创建一个工作流程。&
目前Quartz没有“直接”或者“便捷”的方法能够串行触发器。但是有几种方法可
以完成这些工作而不需要太多的工作。下面是这些方法的介绍:&
一个方法就是使用监听器(例如:TriggerListener,JobListener或者
SchedulerListener)来通知任务/触发器的执行完成,并且立即触发新的触发器。这个方
法会有一些小麻烦,因为你不得不通知接下来要执行任务的监听器,并且你可能会担心这
个信息的持久化问题。&
另一个方法就是建立一个任务,这个任务将下一个要执行任务的名字放在这个任务的
JobDataMap中,当这个任务完成时(它的exceute()方法中的最后一步)就会产生执行
下一个任务的日程安排。有些人使用这个方法并且取得成功。大多数创建一个(虚)基类,
在这个类中,一个任务知道如何通过特定的键来获得JobDataMap以外的任务名和组,
并且包含了将已识别的任务纳入日程的代码,然后,简单地扩展这个类使其包含任务需要
做的附加工作。&
&在将来,Quartz将提供一个非常明确的方法去完成这些功能,但目前为止,你只能
使用以上这些方法中的一种,或者考虑更适合你的方法。&
为什么触发器没有被触发?&
最常见的原因就是没有调用Scheduler.start(),这个方法告知scheduler开始触发触
发器。&
另外一个常见的原因就是触发器或者触发器组被暂停了。&
夏令时和触发器&
CronTrigger&和&SimpleTrigger分别用它们自己的方式来处理夏令时,每种方式
对与触发器类型来说都很直观。&
首先,回顾一下什么是夏令时,请阅读这个资源:
&。&
(夏令时开始的时刻,时钟要向前(未来)拨一个小时,夏令时结束的时刻,时钟向
后(过去)拨一个小时)&
有的读者可能没有意识到不同的国家和地区的夏令时规则是不同的。例如:2005年
美国夏令时开始于4月3日,而埃及则开始于4月29日。不仅夏令时切换日期在不同的
地区不同,时间也不同,有些地方于凌晨两点切换,而其他地方则于凌晨1:00切换,其
他的地方则于凌晨3点切换,并且也有的地方就正好在午夜切换。&
SimpleTrigger允许你每隔若干毫秒来触发纳入进度的任务。因此,对于夏令时来
说,根本不需要做任何特殊的处理来“保持进度”。它只是简单地保持每隔若干毫秒来触
发一次,无论你的SimpleTrigger每隔10秒触发一次还是每隔15分钟触发一次,还是
每隔24小时触发一次。但是这隐含了一个混乱,对于那些每隔12个小时触发一次的
SimpleTrigger来说,在实行夏令时之前,任务是在凌晨3点及下午3点触发,但是在
执行夏令时后,人物是在凌晨4点及下午4点触发。这不是Bug,触发器仍然保持了每隔
若干毫秒触发一次,只是时间的“名字”被人为地强行改变了。&
CronTrigger能在特定&“格林日历”时刻触发纳入进程的任务,因此,如果创建一
个在每天上午10点触发的触发器,那么,在夏令时执行之前,系统将继续如此运作。但
是,取决于是春季还是秋季夏令时,因为对于特定的星期日,从星期六上午10点到星期
日上午10点之间的时间间隔将不是24小时,而可能是23或者25个小时。&
当使用夏令时的时候,对于CronTrigger来说,有一个特别的“时间点”用户必须理
解。这就是你应注意考虑在午夜和凌晨3点(临界的窗口时间取决于所在的地区)之间触
发的任务,其原因就是由于触发器的进度以及特定的夏令时时间造成。触发器可能被忽略
或者一两个小时都没有触发。例如:假设你在美国,这里的夏令时发生在凌晨两点(时钟
会调整为凌晨3:00)。如果CronTrrigger触发在那天的凌晨2:15分,那么,在夏令
时开始的那天,触发器将被忽略。因为,那天凌晨2;15这个事件根本不存在。如果
CronTrigger每15分钟触发一次,那么在夏令时结束的那天,你将会有一个小时的时间
没有触发发生。因为当凌晨2点到达时,时间将重新变成凌晨1:00,由于凌晨一点钟内
的所有触发都已经触发过了,所以,这个时间不会有触发发生,直到时间又到了凌晨2:
00,这时触发才重新开始。&
总之,如果你记住下面的两条规则,则会感觉良好并且很容易记忆:&
.&SimpleTrigger&总是每隔若干秒触发,而同夏令时没有关系。&
.&CronTrigger&总是在给定的时间出发然后计算它下次触发的时
间。如果在给定的日期内没有该时间,则触发器将会被忽略,如
果在给定的日期内该时间发生了两次,它只触发一次。因为是在
第一次触发发生后计算当天下次触发的时间。&
关于JDBCJobStore的问题&
如何提高JDBC-JobStore的性能?&
关于加速JDBC-JobStore的听闻很少。只有一个比较特别。&
首先,很明显的,但不是很特别:&
.&购买运行较好(较快)的用于连接Quartz的计算机和运行数据库的计算机之间网
络设备。&
.&购买较好的(强大的)用于运行数据库的计算机。&
.&购买较好的关系型数据库。&
另外就是比较简单,但是很有效的方法:为Quartz&表建立索引。&
大多数数据库系统都自动按照主键字段自动建立索引,很多数据库也自动按照外键建
立索引。确保作了这些工作,或者对每个表的所有键字段手工建立索引。&
下一步,手工增加额外的索引:最重要的索引就是TRIGGER表的&next_fire_time&
字段和&state&字段上建立的索引。最后(不是很重要),为FIRED_TRIGGERS的每个
字段建立索引。&
创建表索引&
create&index&idx_qrtz_t_next_fire_time&on&qrtz_triggers(NEXT_FIRE_TIME);&
create&index&idx_qrtz_t_state&on&qrtz_triggers(TRIGGER_STATE);&
create&index&idx_qrtz_t_nf_st&on&qrtz_triggers(TRIGGER_STATE,NEXT_FIRE_TIME);&
create&index&idx_qrtz_ft_trig_name&on&qrtz_fired_triggers(TRIGGER_NAME);&
create&index&idx_qrtz_ft_trig_group&on&qrtz_fired_triggers(TRIGGER_GROUP);&
create&index&idx_qrtz_ft_trig_name&on&qrtz_fired_triggers(TRIGGER_NAME);&
create&index&idx_qrtz_ft_trig_n_g&on&
qrtz_fired_triggers(TRIGGER_NAME,TRIGGER_GROUP);&
create&index&idx_qrtz_ft_trig_inst_name&on&
qrtz_fired_triggers(INSTANCE_NAME);&
create&index&idx_qrtz_ft_job_name&on&qrtz_fired_triggers(JOB_NAME);&
create&index&idx_qrtz_ft_job_group&on&qrtz_fired_triggers(JOB_GROUP);&
如果数据服务器重新启动,DB连接不能够正确恢复&
如果你已经使用Quartz创建了数据源连接(通过在quartz属性文件中定义连接参
数),确保使用一个连接验证的查询语句,例如:&
连接验证查询语句&
org.quartz.dataSource.myDS.validationQuery=select&0&from&dual&
这个特定的查询语句只是针对Oracle。对于其他的数据库,可能要考虑一个只要在连
接正常的时候就能有效执行的查询语句。&
如果数据源被应用服务器所管理,确保数据源被配置成能够检查连接失败的方式。&
关于事务的问题&
使用JobStoreCMT并且发现了死锁,该如何做?&
JobStoreCMT是一个多人使用的、大量负载的重量级应用。确信它是没有导致死锁
的Bug。但是,我们不时地收到有关死锁的抱怨。到目前为止,这些问题都被证明为“用
户错误”。因此,如果你遇到了死锁,下面列表列出了你需要的检查项:&
.&当一个TX执行较长的时间时,数据库错误地检测为死锁。确保你对表建立了索引
(参见提高JDBCJobStore性能)。&
.&确保数据源中有至少线程池中线程数量+2的连接。&
.&确保为使用Quartz配置了管理数据源和非管理数据源。&
.&确保所有使用Scheduler接口完成的工作都在一个事务中。完成这些需要在一个
TX被设置为&Required&或者&Container&的SessionBean中使用Scheduler,
或者在一个有相同设置的MessageDrivenBean中使用Scheduler。最后,自己
开启一个UserTransaction,并且在工作做完时提交它。&
.&如果在任务execute()方法中使用了Scheduler,确保通过UserTransaction或
者设置Quartz的属性:
&org.quartz.scheduler.wrapJobExecutionInUserTransaction=true&来使事
务在进行中。&
.&下载Quartz&
.&安装&Quartz&
.&从源码自己构建Quartz&
.&按照自己特定的需要配置Quartz&
.&开始一个简单的应用&
注意,写这篇文档的时候,Quartz的版本是1.4.3。无论何时,指南都是版本无关的,
只是需要了解这个事实。&
下载和安装&
访问&&并且点击Quartz&1.x包旁边的
download连接下载quratz。&
.&Quartz&1.x(.zip)&–&zip格式的主Quartz&包。(主要为Windows用户准备)&
.&Quartz&1.4.3&(.tar.gz)&-&in&tar/gzip主Quartz&包。(主要为*nix用户准备)&
.&Quartz&Web-App&-&Quartz&web&应用,它能让你通过web接口来监控scheduler。&
下载和解压缩这些文件,然后将其安装在应用可以看到的地方就可以了。&
所需的&JAR文件&
Quartz包括了一系列的jar&文件,&这些文件位于Quartz主目录的lib目录中。主
Quartz&类库被形象地命名为quartz.jar。为了使用&Quartz的特性,&这个jar文件必
须位于classpath中。&
Quartz依赖一系列Jar文件,要使用Quartz,所有这些Jar文件都必须位于
classpath中。&
The&properties&file&
Quartz使用一个名为quartz.properties.的配置文件,开始时这个文件不是必
须的,但是如果使用除了最基本的功能之外的其它功能,则该文件必须位于classpath中。&
从源码自己构建Quartz&
查看release文档来获得buildQuartz的信息。(一般不需要开发者自己构造)&
Quartz是一个可配置性非常强的应用,最佳的配置方法就是编辑quartz.properties
文件。&
首先看的是example_quartz.properties,这个文件位于Quartz主目录下的
docs\wikidocs目录中。也可以点击下列连接查看。&
.&example_quartz.properties&
建议你在例子文件的基础上创建自己的quartz.properties&文件而不是拷贝
example_quartz.properties文件并且删除那些你不需要的内容。通过这种方式,你会
发现更多Quartz&所提供的功能。&
注意:&example_quartz.properties&并没有包括所有可能的属性。&
为了快速建立和运行基于quartz&的应用,基本的quartz.properties&内容如下:&
org.quartz.scheduler.instanceName&=&Sched1&
org.quartz.scheduler.instanceId&=&1&
org.quartz.scheduler.rmi.export&=&false&
org.quartz.scheduler.rmi.proxy&=&false&
org.quartz.threadPool.class&=&org.quartz.simpl.SimpleThreadPool&
org.quartz.threadPool.threadCount&=&3&
org.quartz.jobStore.class&=&org.quartz.simpl.RAMJobStore&
依据这个配置文件创建的scheduler有如下特性:&
.&org.quartz.scheduler.instanceName&–&它叫做&Sched1&&(doh)&
.&org.quartz.scheduler.rmi.export&–&这个scheduler是本地的,&这意味着它不能
通过RMI(Remote&Method&Invocation)进行访问。&
.&org.quartz.threadPool.threadCount&–在线程池中有3个线程,这意味着最多有3
个线程可以并发运行。&
.&org.quartz.jobStore.class&–&所有的Quartz数据,例如Job和Trigger的细节信息
被存储在内存(而不是数据库)中。&
尽管你有一个数据库并且希望Quartz使用这个数据库,建议你在使用数据库之前先使
用RamJobStore进行工作。
开始一个简单的应用&
现在你已经下载安装了Quartz,应当创建一个简单的应用并且运行这个应用。下面
的代码包括了如何实例化一个scheduler,启动它并且关闭它。&
QuartzTest.java&
import&org.quartz.S&
import&org.quartz.SchedulerE&
import&org.quartz.impl.StdSchedulerF&
public&class&QuartzTest&{&
&public&static&void&main(String[]&args)&{&
&//&Grab&the&Scheduler&instance&from&the&Factory&
&Scheduler&scheduler&=&StdSchedulerFactory.getDefaultScheduler();&
&//&and&start&it&off&
&scheduler.start();&
&scheduler.shutdown();&
&}&catch&(SchedulerException&se)&{&
&se.printStackTrace();&
注意:一旦通过StdSchedulerFactory.getDefaultScheduler()获得一个scheduler&,
那么应用将不会结束,除非调用scheduler.shutdown()方法。
如果没有建立日志机制,所有的日志都将被发送到控制台,并且输出如下样子的信息:&
16-Dec-:21&org.quartz.simpl.SimpleThreadPool&initialize&
INFO:&Job&execution&threads&will&use&class&loader&of&thread:&main&
16-Dec-:22&org.quartz.simpl.RAMJobStore&initialize&
INFO:&RAMJobStore&initialized.&
16-Dec-:22&org.quartz.impl.StdSchedulerFactory&instantiate&
INFO:&Quartz&scheduler&'DefaultQuartzScheduler'&initialized&from&default&
resource&file&in&Quartz&package:&'quartz.properties'&
16-Dec-:22&org.quartz.impl.StdSchedulerFactory&instantiate&
INFO:&Quartz&scheduler&version:&1.4.2&
16-Dec-:22&org.quartz.core.QuartzScheduler&start&
INFO:&Scheduler&DefaultQuartzScheduler_$_NON_CLUSTERED&started.&
16-Dec-:22&org.quartz.core.QuartzScheduler&shutdown&
INFO:&Scheduler&DefaultQuartzScheduler_$_NON_CLUSTERED&shutting&down.&
16-Dec-:22&org.quartz.core.QuartzScheduler&pause&
INFO:&Scheduler&DefaultQuartzScheduler_$_NON_CLUSTERED&paused.&
16-Dec-:22&org.quartz.core.QuartzScheduler&shutdown&
INFO:&Scheduler&DefaultQuartzScheduler_$_NON_CLUSTERED&shutdown&complete.&
Quartz官方开发指南&
1.&第一课:使用Quartz&
2.&第二课:Jobs&And&Triggers&
3.&第三课:更多关于Jobs和JobDetails的内容&
4.&第四课:关于Triggers更多的内容&
5.&第五课:SimpleTriggers&
6.&第六课:&CronTriggers&
7.&第七课:&TriggerListeners和JobListeners&
8.&第八课:&SchedulerListeners&
9.&第九课:&JobStores&
10.&第十课:&Configuration,&Resource&使用及SchedulerFactory&
11.&第十一课:&高级(企业级)特性&
12.&第十二课:&其他特性&
第一课:使用Quartz&
使用scheduler之前应首先实例化它。使用SchedulerFactory可以完成scheduler
的实例化。有些Quartz用户将工厂类的实例放在JNDI中存储,其他用户可能直接地实
例化这个工厂类并且直接使用工厂的实例(例如下面的例子)。&
一旦一个scheduler被实例化,它就可以被启动(start),并且处于驻留模式,直到被
关闭(shutdown)。注意,一旦scheduler被关闭(shutdown),则它不能再重新启动,
除非重新实例化它。除非scheduler&被启动或者不处于暂停状态,否则触发器不会被触
发(任务也不能被执行)。&
下面是一个代码片断,这个代码片断实例化并且启动了一个scheduler,接着将一个
要执行的任务纳入了进程。&
Using&Quartz&
SchedulerFactory&schedFact&=&new&org.quartz.impl.StdSchedulerFactory();&
Scheduler&sched&=&schedFact.getScheduler();&
sched.start();&
JobDetail&jobDetail&=&new&JobDetail(&myJob&,null,DumbJob.class);&
Trigger&trigger&=&TriggerUtils.makeHourlyTrigger();&//每个小时激活一次&
trigger.setStartTime(TriggerUtils.getEvenHourDate(new&Date()));//在下一个
小时启动。&
trigger.setName(&myTrigger&);&
sched.scheduleJob(jobDetail,&trigger);&
如您所见,使用quartz相当简单,在第二课中,我们将给出一个Job和Trigger的
快速预览,这样就能够充分理解这个例子。&
第二课Jobs&And&Triggers&
正如前面所提到的那样,通过实现Job接口来使你的Java组件可以很简单地被
scheduler执行。下面是Job接口:&
Job&Interface&
package&org.&
public&interface&Job&{&
&public&void&execute(JobExecutionContext&context)&
&throws&JobExecutionE&
&这样,你会猜想出,当Job触发器触发时(在某个时刻),execute(..)就被scheduler
所调用。JobExecutionContext对象被传递给这个方法,它为Job实例提供了它的“运
行时”环境-一个指向执行这个Job实例的Scheduler句柄,一个指向触发该次执行的触
发器的句柄,Job的JobDetail对象以及一些其他的条目。&
JobDetail对象由Quartz客户端在Job被加入到scheduler时创建。它包含了Job
的各种设置属性以及一个JobDataMap对象,这个对象被用来存储给定Job类实例的
状态信息。&
&Trigger对象被用来触发jobs的执行。你希望将任务纳入到进度,要实例化一个
Trigger并且“调整”它的属性以满足你想要的进度安排。Triggers也有一个JobDataMap
与之关联,这非常有利于向触发器所触发的Job传递参数。Quartz打包了很多不同类型
的Trigger,但最常用的Trigge类是SimpleTrigger和CronTrigger。&
SimpleTrigger用来触发只需执行一次或者在给定时间触发并且重复N次且每次执
行延迟一定时间的任务。CronTrigger按照日历触发,例如“每个周五”,每个月10日
中午或者10:15分。&
为什么要分为Jobs和Triggers?很多任务日程管理器没有将Jobs和Triggers进行
区分。一些产品中只是将“job”简单地定义为一个带有一些小任务标识的执行时间。其
他产品则更像Quartz中job和trigger的联合。而开发Quartz的时候,我们决定对日
程和按照日程执行的工作进行分离。(从我们的观点来看)这有很多好处。&
例如:jobs可以被创建并且存储在job&scheduler中,而不依赖于trigger,而且,
很多triggers可以关联一个job.另外的好处就是这种“松耦合”能使与日程中的Job相
关的trigger过期后重新配置这些Job,这样以后就能够重新将这些Job纳入日程而不必重
新定义它们。这样就可以更改或者替换trigger而不必重新定义与之相连的job标识符。&
当向Quartz&scheduler中注册Jobs&和Triggers时,它们要给出标识它们的名字。
Jobs&和Triggers也可以被放入“组”中。“组”对于后续维护过程中,分类管理Jobs
和Triggers非常有用。Jobs和Triggers的名字在组中必须唯一,换句话说,Jobs和
Triggers真实名字是它的名字+组。如果使Job或者Trigger的组为‘null’,这等价于
将其放入缺省的Scheduler.DEFAULT_GROUP组中。&
现在对什么是Jobs&和&Triggers有了一般性的认识,可以通过第三课:更多关于Jobs
和JobDetails的内容及第四课:关于Triggers更多的内容来深入地学习它们。&
第三课:更多关于Jobs和JobDetails的内容&
如你所见,Job相当容易实现。这里只是介绍有关Jobs本质,&Job接口的execute(..)
方法以及JobDetails中需要理解的内容。&
在所实现的类成为真正的“Job”时,期望任务所具有的各种属性需要通知给Quartz。
通过JobDetail类可以完成这个工作,这个类在前面的章节中曾简短提及过。软件“考古
学家”们可能对了解Quartz早期版本的样子感兴趣。早期的Quartz中,JobDetail实
现的功能被强加给实现Job的类,实现Job的类必须实现Job接口中所有同JobDetail
类一样的'getter'方法。这样为每个Job类强加了一个重新实现虚拟识别码的笨重工作,
这实在糟糕,因此,我们创建了JobDetail类。&
现在,我们花一些时间来讨论Quartz中Jobs的本质和Job实例的生命周期。首先
让我们回顾一下第一课中所看到的代码片断:&
Using&Quartz&
JobDetail&jobDetail&=&new&JobDetail(&myJob&,&//&job&名&
&sched.DEFAULT_GROUP,&//&job&组(你可
以指定为'null'以使用缺省的组)&
&DumbJob.class);&//&要被执行的Java类。&
&Trigger&trigger&=&TriggerUtils.makeDailyTrigger(8,&30);&
&trigger.setStartTime(new&Date());&
&trigger.setName(&myTrigger&);&
&sched.scheduleJob(jobDetail,&trigger);&
现在考虑如下定义的DumbJob类:&
public&class&DumbJob&implements&Job&{&
&public&DumbJob()&{&
&public&void&execute(JobExecutionContext&context)&
&throws&JobExecutionException&
&System.err.println(&DumbJob&is&executing.&);&
注意,我们给scheduler传入了一个JobDetail实例,而且这个JobDetail实例只
是简单提供了类名来引用被执行的Job。每次scheduler执行这个任务时,它就创建这个
类的新实例,然后调用该实例的execute(..)方法。对这种行为的一个推论就是Job类必
须有一个无参数的构造函数。另外一个推论就是它使得Job类中定义的成员数据失去意义,
因为这些成员数据值在每次执行的时候被“清空”了。&
你可能要问,如何才能为每个Job实例提供属性和配置呢?而且,在执行中如何跟踪
Job的状态呢?这些问题的答案是相同的:关键就是JobDataMap,这是JobDetail对象
的一部分。&
JobDataMap&
JobDataMap被用来保存一系列的(序列化的)对象,这些对象在Job执行时可以
得到。JobDataMap是Java&Map接口的一个实现,而且还增加了一些存储和读取主类
型数据的便捷方法。&
下面是将Job加入到scheduler前使用的一些向JobDataMap加入数据的方法。&
Setting&Values&in&a&JobDataMap&
jobDetail.getJobDataMap().put(&jobSays&,&&Hello&World!&);&
jobDetail.getJobDataMap().put(&myFloatValue&,&3.141f);&
jobDetail.getJobDataMap().put(&myStateData&,&new&ArrayList());&
下面的代码展示了在Job执行过程中从JobDataMap&获取数据的代码:&
Getting&Values&from&a&JobDataMap&
public&class&DumbJob&implements&Job&{&
&public&DumbJob()&{&
&public&void&execute(JobExecutionContext&context)&
&throws&JobExecutionException&
&String&instName&=&context.getJobDetail().getName();&
&String&instGroup&=&context.getJobDetail().getGroup();&
&JobDataMap&dataMap&=&context.getJobDetail().getJobDataMap();&
&String&jobSays&=&dataMap.getString(&jobSays&);&
&float&myFloatValue&=&dataMap.getFloat(&myFloatValue&);&
&ArrayList&state&=&(ArrayList)dataMap.get(&myStateData&);&
&state.add(new&Date());&
&System.err.println(&Instance&&&+&instName&+&&&of&DumbJob&says:&&&+&
jobSays);&
如果使用一个持久的JobStore(在本指南的JobStore章节中讨论),那么必须注
意存放在JobDataMap中的内容。因为放入JobDataMap中的内容将被序列化,而且容
易出现类型转换问题。很明显,标准Java类型将是非常安全的,但除此之外的类型,任
何时候,只要有人改变了你要序列化其实例的类的定义,就要注意是否打破了程序的兼容
性。有关这方面的更多信息可以在Java&Developer&Connection&Tech&Tip:&
Serialization&In&The&Real&World中找到。另外,你可以对JobStore和JobDataMap
采用一种使用模式:就是只把主类型和String类型存放在Map中,这样就可以减少后面
序列化的问题。&
有状态和无状态任务&
Triggers也可以有JobDataMaps与之相关联。当scheduler中的Job被多个有规
律或者重复触发的Triggers所使用时非常有用。对于每次独立的触发,你可为Job提供
不同的输入数据。&
从Job执行时的JobExecutionContext中取得JobDataMap是惯用手段,它融合
了从JobDetail和从Trigger中获的JobDataMap,当有相同名字的键时,它用后者的
值覆盖前者值。下面的代码就是在Job执行过程中从JobExecutionContext's获取融合
的JobDataMap。&
Getting&Values&from&the&JobExecutionContext&convenience/merged&
JobDataMap&
public&class&DumbJob&implements&Job&{&
&public&DumbJob()&{&
&public&void&execute(JobExecutionContext&context)&
&throws&JobExecutionException&
&String&instName&=&context.getJobDetail().getName();&
&String&instGroup&=&context.getJobDetail().getGroup();&
&JobDataMap&dataMap&=&context.getJobDataMap();&//&注意同前面例子的不同
&String&jobSays&=&dataMap.getString(&jobSays&);&
&float&myFloatValue&=&dataMap.getFloat(&myFloatValue&);&
&ArrayList&state&=&(ArrayList)dataMap.get(&myStateData&);&
&state.add(new&Date());&
&System.err.println(&Instance&&&+&instName&+&&&of&DumbJob&says:&&&+&
jobSays);&
有个神奇的问题,动态的添加定时任务(包含添加监听),实例化到数据库后,重启服务,监听失效,楼主遇到过么
贴吧热议榜
使用签名档&&
保存至快速回贴

我要回帖

更多关于 quartz长时间任务 的文章

 

随机推荐