quartz

Quartz 是一个强大的企业级 Schedule 工具,也是目前最好的开源 Schedule 工具。Spring中也集成了quartz的应用,下面就讲一下如何在spring中使用quartz。

spring的配置:
xml 代码

1. <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
2. <property name="triggers">
3. <list>
4. <ref bean="simpleTrigger"/>
5. <ref bean="cornTrigger"/>
6. </list>
7. </property>
8. </bean>
9. <bean id="schedulerControl" class="com.pheh.scheduler.Schedule">
10. <property name="scheduler">
11. <ref bean="schedulerFactoryBean"/>
12. </property>
13. </bean>
14.
15. <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
16. <property name="jobDetail">
17. <ref bean="methodInvokingJobDetail"/>
18. </property>
19. <property name="startDelay">
20. <value>1000</value>
21. </property>
22. <property name="repeatInterval">
23. <value>3000</value>
24. </property>
25. </bean>
26. <bean id="cornTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
27. <property name="jobDetail">
28. <ref bean="methodInvokingJobDetail"/>
29. </property>
30. <property name="cronExpression">
31. <value>0 0 */1 * * ?</value>
32. </property>
33. </bean>
34.



Job:
org.quartz.Job是一个接口,只定义了void execute(JobExecutionContext context)throws JobExecutionException;一个方法。当定时任务被触发后,系统会自动调用实现了该接口的方法。在spring 中,org.springframework.scheduling.quartz.QuartzJobBean对其进行了封装,使用了Template Method模式。主要是为了在使用jobDataMap时更加方便。QuartzJobBean有两个方法,
public final void execute(JobExecutionContext context) throws JobExecutionException
Job接口中定义的,spring在该方法里进行了些处理,将jobDataMap中的值注入到该Job的实现者中

protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException
这是一个抽象方法,用户在扩展了QuartzJobBean后,要自己实现该方法,在其中添加相应的业务逻辑

JobDetail:
JobDetail描述了一个任务具体的信息。在Spring中,JobDetailBean对JobDetail进行了封装(继承了JobDetail)。
private String name;//名称
private String group = Scheduler.DEFAULT_GROUP;//组
private String description;//描述
private Class jobClass;//定时任务触发时,回调的class,该class要实现Job接口或继承QuartzJobBean
private JobDataMap jobDataMap;//该任务存储的数据,在回调的时候也可以使用
private boolean volatility = false;//是否持久化到org.quartz.spi.JobStore中
private boolean durability = false;//当该任务完成后,是否还在JobStore中继续保留该任务
private boolean shouldRecover = false;//当系统重新启动后,是否再次执行该任务
对于jobDataMap,它是是一个封装过的Map,使用方法同Map,如
jobDetailBean.getJobDataMap().put(target,value);
如果使用了QuartzJobBean,在使用jobDetailBean时,可将target的值设成QuartzJobBean的子类的属性名称,这样,在定时触发时,spring会自动将与target对应的value值注入到QuartzJobBean的子类中去。如。
java 代码

1. ...
2. public class ReminderManager extends QuartzJobBean{
3. private String reminderStr = "";
4. }
5. ...
6. jobDetailBean.getJobDataMap().put(reminderStr,"abcdefg");
7. ...


这样当该任务被触发后,在ReminderManager中,reminderStr的值就会被注入为"abcdefg"。

Trigger:
trigger就是触发器。Quartz有个很好的想法就是分离了任务和任务执行的条件。Trigger就是控制任务执行条件的类,当Trigger认为执行条件满足的时刻,Trigger会通知相关的Job去执行。分离的好处是:
1.你可以为某个Job关联多个Trigger,其中任何一个条件满足都可以触发job执行,这样可以完成一些组合的高级触发条件
2.当Trigger失效后(比如:一个永远都不能满足的条件),你不必去声明一个新的job,代替的是你可以为job关联一个新的Trigger让job可以继续执行。
目前的Quartz实现中,存在两种Trigger,SimpleTrigger和CronTrigger,在spring中分别用 SimpleTriggerBean和CronTriggerBean对其进行封装。SimpleTrigger是简单触发器,如从某日到某日,每个一定时间进行一次提醒,在这段时间内进行多少次提醒;CronTrigger是复杂触发器,用来执行calendar-like的任务,可设定一些复杂的触发规则,如每年的x月的第y个星期五,或是每个星期天的几点进行提醒。后面附加一个日常语义与cronTrigger的转化

Trigger
private String name;//名称
private String group = Scheduler.DEFAULT_GROUP;//组
private String jobName;//所关联的jobDetail的名称
private String jobGroup = Scheduler.DEFAULT_GROUP;//所关联的jobDetail的组
private String description;//描述
private JobDataMap jobDataMap;//该触发器存储的数据,在回调的时候也可以使用
private boolean volatility = false;//是否持久化到org.quartz.spi.JobStore中

SimpleTrigger
private Date startTime = null;//开始日期
private Date endTime = null;//结束日期
private Date nextFireTime = null;//下次的触发时间
private Date previousFireTime = null;//上次的触发时间
private int repeatCount = 0;//重复次数
private long repeatInterval = 0;//重复间隔
private int timesTriggered = 0;/已触发的次数

SimpleTriggerBean
private JobDetail jobDetail;//所关联的JobDetail,方便在配置文件中使用

CornTrigger
private CronExpression cronEx = null;//触发条件表达式,它有一个String型的setter
private Date startTime = null;//开始日期
private Date endTime = null;//结束日期
private Date nextFireTime = null;//下次的触发时间
private Date previousFireTime = null;//上次的触发时间
private transient TimeZone timeZone = null;//所在时区

CronTriggerBean
private JobDetail jobDetail;//所关联的JobDetail,方便在配置文件中使用

Scheduler的常用方法
添加一个定时任务:
Date scheduleJob(JobDetail jobDetail,Trigger trigger)

修改一个定时任务,主要是更改trigger:
Date rescheduleJob(String triggerName, String groupName, Trigger newTrigger)

删除一个定时任务,同时也会将于该jobDetail关联的trigger一并删除:
boolean deleteJob(String jobName,String jobGroup)

取得所有的jobDetail组
String[] getJobGroupNames()

取得某个group下的所有的jobDetail
String[] getJobNames(String groupName)

取得指定的jobDetail
JobDetail getJobDetail(String jobName, String jobGroup)

取得指定的jobDetail的所有的Trigger
Trigger[] getTriggersOfJob(String jobName, String groupName)

取得指定的Trigger
Trigger getTrigger(String triggerName, String triggerGroup)

Quartz的存储:
Quartz默认的是使用RAM存储所有的信息,但是这样的话,当我们重启服务器后,之前的所有的定时任务就全消失了。为了让服务器重启以后,我们的定时任务仍不丢失,我们可采用数据库持久化定时任务。
首先要先建立数据库,在quartz-1.6.0\docs\dbTables下,选择自己使用的数据库的sql脚本,建立相应的数据库表。
在WEB-INF下加一个quartz.properties。我们可以在 quartz-1.6.0\examples\example10 中找到该文件的样例



org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX #表明使用JDBC进行持久化
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_ #该值尽量不要改动,如改动,还要相应的修改sql脚本
org.quartz.jobStore.isClustered = false

org.quartz.dataSource.myDS.driver = net.sourceforge.jtds.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:jtds:sqlserver://192.168.1.101:1433/Northwind;autoReconnect=true
org.quartz.dataSource.myDS.user = sa
org.quartz.dataSource.myDS.password =
org.quartz.dataSource.myDS.maxConnections = 5

日常语义与cronTrigger的转化,以下setter,getter省略


java 代码

1. public class TDateRange{
2. private int startType = 2;//开始类型。默认的使用2表示使用开始日期
3. private Date startDate = new Date();//开始日期
4. private int endType = 0;//结束类型。0表示无结束时间;1表示重复n次后结束;2表示使用结束日期
5. private Date endDate = new Date();//结束日期
6. private int occurrences;//执行次数
7. }
8. public class TFrequency{
9. //0:无重复提醒
10. //1:每every
11. //2:每个工作日detail=1,2,3,4,5
12. //3:每every周后的星期detail日
13. //4:每every月的detail日
14. //5:每every月的第num1个星期num2
15. //6:每年num1月num2日
16. //7:每年every月的第num1个月的星期num2
17. private int type = 0;//频率类型
18. private int every = 0;
19. private String detail = "";
20. private String num1 = "";
21. private String num2 = "";
22. }
23.
24. private String formatQuartzString(){
25. String quartzStr = "";
26. tiggernote="";
27. //秒 分 时
28. quartzStr = "0 "+this.dateRange.getStartDate().getMinutes()+" "+this.dateRange.getStartDate().getHours()+" ";
29. switch(this.frequency.getType()){
30. case 0://无重复提醒
31. quartzStr += this.dateRange.getStartDate().getDate()+" "+(this.dateRange.getStartDate().getMonth()+1)+" ? "+(this.dateRange.getStartDate().getYear()+1900);
32. tiggernote+="起始时间:"+quartzStr;
33. break;
34. case 1://每XX天提醒
35. quartzStr += "*/"+this.frequency.getEvery()+" * ? ";
36. tiggernote+="每"+this.frequency.getEvery()+"提醒";
37. break;
38. case 2://每个工作日detail=1,2,3,4,5
39. //quartzStr += "? * 2-6";
40. quartzStr ="0 */1 * * * ?"; //测试
41. tiggernote+="每个工作日1,2,3,4,5提醒";
42. break;
43. case 3://每every周后的星期detail日
44. quartzStr += "? * "+this.frequency.getDetail()+"/"+this.frequency.getEvery();
45. tiggernote+="每"+this.frequency.getEvery()+"周星期"+this.frequency.getDetail()+"日";
46. break;
47. case 4://每every个月的detail日
48. quartzStr += this.frequency.getDetail()+" */"+this.frequency.getEvery()+" ?";
49. tiggernote+="每"+this.frequency.getEvery()+"月"+this.frequency.getDetail()+"日";
50. break;
51. case 5://每every个月的第num1个星期num2
52. quartzStr += "? */"+this.frequency.getEvery()+" "+this.frequency.getNum2();
53. //星期
54. if(Integer.valueOf(this.frequency.getNum1()).intValue()>0){
55. quartzStr += "#"+this.frequency.getNum1();
56. tiggernote+="每"+this.frequency.getEvery()+"月第"+this.frequency.getNum1()+"个星期"+this.frequency.getNum2()+"日";
57. }else{
58. quartzStr += "L";
59. tiggernote+="每"+this.frequency.getEvery()+"月星期"+this.frequency.getNum2();
60. }
61. break;
62. case 6://每年num1月num2日
63. quartzStr += this.frequency.getNum2()+" "+this.frequency.getNum1()+" ?";
64. tiggernote+="每年"+this.frequency.getNum1()+"月"+this.frequency.getNum2()+"日";
65. break;
66. case 7://每年every月的第num1个星期num2
67. quartzStr += "? "+this.getFrequency().getEvery()+" "+this.getFrequency().getNum2();
68. //星期
69. if(Integer.valueOf(this.frequency.getNum1()).intValue()>0){
70. quartzStr += "#"+this.frequency.getNum1();
71. tiggernote+="每年"+this.getFrequency().getEvery()+"月的第"+this.frequency.getNum1()+"个星期"+this.getFrequency().getNum2()+"日";
72. }else{
73. quartzStr += "L";
74. tiggernote+="每年"+this.getFrequency().getEvery()+"月的"+this.getFrequency().getNum2()+"日";
75. }
76. break;
77. default :
78. }
79. log.debug("quartzStr="+quartzStr);
80. return quartzStr;
81. }

Scheduler:
Scheduler 是一个计划集,其中可以包含多个 JobDetail 和 Trigger 组成的计划任务。
在Quartz中,我们可以通过
SchedulerFactory scheduleFactory = new StdSchedulerFactory();
Scheduler scheduler = scheduleFactory.getScheduler();
来取得scheduler,通过调用scheduler.start()来启动quartz。
在spring中,org.springframework.scheduling.quartz.SchedulerFactoryBean是对 Quartz的org.quartz.Scheduler的封装,通过上面的配置,在spring启动的时候,quartz就会跟随着启动,不需要再用 scheduler.start()来启动。在spring中,如果要取得scheduler,可通过上面的配置文件那样,将 SchedulerFactoryBean注入到schdeuler中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值