java 中已经有一个 timer 类可以用来进行执行计划,定时任务。我们所要做的只是继承 java.util.timertask 类。如下所示:
package com.yourcompany.scheduling;
import java.util.calendar;
import java.util.date;
import java.util.timer;
import java.util.timertask;
public class reportgenerator extends timertask {
public void run() {
system.out.println("generating report");
//todo generate report
}
}
class mainapplication {
public static void main(string[] args) {
timer timer new timer();
calendar date = calendar.getinstance();
date.set(calendar.day_of_week,calendar.sunday);
date.set(calendar.hour, 0);
date.set(calendar.minute, 0);
date.set(calendar.second, 0);
date.set(calendar.millisecond, 0);
// schedule to run every sunday in midnight
timer.schedule(new reportgenerator(), // timertask
date.gettime(), // timer
1000 * 60 * 60 * 24 * 7 // delay)
};
这里有几个问题,我们的类继承了timertask ,而timertask 也是实现了 java.lang.runnable 接口。我们所要做的只是在我们自己的类里重置 run() 方法。所以我们的timertask类其实是一种线程,但线程的调度往往不是按照我们希望来实现的,因为一些垃圾收集等原因,我们计划的时间点,却没有执行必要的任务。这样会产生一些问题。虽然,timer 类也提供了scheduleatfixedrate() 方法用来在垃圾收集后能够快速的追上任务进度,但这个不一定是我们所需要的。特别是在 一些 j2ee 服务器上 timer 是无法控制的,因为它不在容器的权责范围内。另外的,这个任务调度也缺乏一些企业级所需要的 特殊 日期定制的功能,以及修改,查找任务的功能。
这里我们要介绍的是一个开源项目:quartz .
quartz 定义了两种 基本接口 job 和 trigger . 看名字也就知道,我们的任务必须实现 job, 我们的时间触发器定义在 trigger 内。 看一个例子也许能更快的了解他的使用方法:package com.yourcompany.scheduling;
import org.quartz.*;
public class quartzreport implements job {
public void execute(jobexecutioncontext cntxt) //必须实现的方法
throws jobexecutionexception {
system.out.println("generating report - " +
cntxt.getjobdetail().getjobdatamap().get("type"));
//todo generate report
}
public static void main(string[] args) {
try {
schedulerfactory schedfact
new org.quartz.impl.stdschedulerfactory();
scheduler sched = schedfact.getscheduler();
sched.start();
jobdetail jobdetail = new jobdetail("income report", // 任务名
"report generation", // 任务组
quartzreport.class //任务执行的类
);
jobdetail.getjobdatamap().put("type","full");
crontrigger trigger new crontrigger(
"income report", //触发器名
"report generation" //触发器组
);
trigger.setcronexpression( // 触发器时间设定
"0 0 12 ? * sun"
);
sched.schedulejob(jobdetail, trigger); // 执行任务
}
catch (exception e) {
e.printstacktrace();
}
这里面我们可以看到,当我们定义了任务执行 quartzreport 类后,需要定一个scheduler类用来执行计划任务。
一个jobdetail 类来描述这个任务的信息,包括任务信息,任务所在组,任务执行的类。
然后还要定义一个 触发器,类似的也包括触发器名,触发器所在组,触发器触发时间设定。
最后是调度器scheduler类执行计划任务。基本上一个计划任务执行的流程就完成了。
当然,我们还看到了上面红色代表的内容,这些内容主要是提供在job方法执行的时候所需要的参数的提供。这里使用了jobdatamap 类,它其实就是实现了map的特殊应用的一个类,使用方法与map 很相似。我们可以用 put() 输入参数。在job类中使用cntxt.getjobdetail()。getjobdatamap()。get("type") 方法获取输入的参数的值。这里的cntxt 是 jobexecutioncontext .就是包含任务执行上下文的一个信息类。这样我们的一个基本的任务执行就可以搞定了。
触发器有两类:simpletrigger andcrontrigger. .simpletrigger主要提供了跟 java.util.timer 类相似的功能……你可以在里面定义 任务的起始时间,终止时间,任务的执行次数,任务执行的中间间隔 . 而 crontrigger类主要提供了更高级的任务调度时间设置,例如 每个星期天的早上7点 . crontrigger的时间设置说明在最后来介绍。
下面我们介绍一下在 j2ee 环境下如何来使用 quartz .
首先,我们要配置 web.xml ,添加 一下内容,主要是quartz 的初始化,
<servlet>
<servlet-name>quartzinitializer</servlet-name>
<display-name>quartz initializer servlet</display-name>
<servlet-class>org.quartz.ee.servlet.quartzinitializerservlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
然后还要有一个quartz 的配置文件 quartz.properties 放置在 web-inf/classes目录下面。stdschedulefactory()会读取它。配置如下#
# configure main scheduler properties
#
org.quartz.scheduler.instancename = testscheduler
org.quartz.scheduler.instanceid = one
#
# configure threadpool
#
org.quartz.threadpool.class = org.quartz.simpl.simplethreadpool
org.quartz.threadpool.threadcount = 5
org.quartz.threadpool.threadpriority = 4
#
# configure jobstore
#
org.quartz.jobstore.misfirethreshold = 5000
org.quartz.jobstore.class = org.quartz.simpl.ramjobstore
这里我们使用的 ramjobstore 存储方式,这样如果我们的web服务器重启的话,我们所有未执行的任务信息都回丢失。当然,我们也有另外的选择,我们可以把这样的信息存储在数据库内,就是使用 jdbcjobstoretx
#
# configure threadpool
#
org.quartz.jobstore.class = org.quartz.impl.jdbcjobstore.jobstoretx
org.quartz.jobstore.driverdelegateclass = org.quartz.impl.jdbcjobstore.postgresqldelegate
org.quartz.jobstore.datasource = myds org.quartz.jobstore.tableprefix = qrtz_
#
# configure datasources
#
org.quartz.datasource.myds.driver = org.postgresql.driver
org.quartz.datasource.myds.url = jdbc:postgresql:dev
org.quartz.datasource.myds.user = dejanb
org.quartz.datasource.myds.password = org.quartz.datasource.myds.maxconnections 5
附:cronexpression配置说明
字段 |
| 允许值 |
| 允许的特殊字符 |
秒 |
| 0-59 |
| , - * / |
分 |
| 0-59 |
| , - * / |
小时 |
| 0-23 |
| , - * / |
日期 |
| 1-31 |
| , - * ? / l w c |
月份 |
| 1-12 或者 jan-dec |
| , - * / |
星期 |
| 1-7 或者 sun-sat |
| , - * ? / l c # |
年(可选) |
| 留空, 1970-2099 |
| , - * / |
表示方式 | 意义 |
"0 0 12 * * ?" | fire at 12pm (noon) every day |
"0 15 10 ? * *" | fire at 10:15am every day |
"0 15 10 * * ?" | fire at 10:15am every day |
"0 15 10 * * ? *" | fire at 10:15am every day |
"0 15 10 * * ? 2005" | fire at 10:15am every day during the year 2005 |
"0 * 14 * * ?" | fire every minute starting at 2pm and ending at 2:59pm, every day |
"0 0/5 14 * * ?" | fire every 5 minutes starting at 2pm and ending at 2:55pm, every day |
"0 0/5 14,18 * * ?" | fire every 5 minutes starting at 2pm and ending at 2:55pm, and fire every 5 minutes starting at 6pm and ending at 6:55pm, every day |
"0 0-5 14 * * ?" | fire every minute starting at 2pm and ending at 2:05pm, every day |
"0 10,44 14 ? 3 wed" | fire at 2:10pm and at 2:44pm every wednesday in the month of march. |
"0 15 10 ? * mon-fri" | fire at 10:15am every monday, tuesday, wednesday, thursday and friday |
"0 15 10 15 * ?" | fire at 10:15am on the 15th day of every month |
"0 15 10 l * ?" | fire at 10:15am on the last day of every month |
"0 15 10 ? * 6l" | fire at 10:15am on the last friday of every month |
"0 15 10 ? * 6l" | fire at 10:15am on the last friday of every month |
"0 15 10 ? * 6l 2002-2005" | fire at 10:15am on every last friday of every month during the years 2002, 2003, 2004 and 2005 |
"0 15 10 ? * 6#3" | fire at 10:15am on the third friday of every month |
闽公网安备 35060202000074号