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
);
}
}
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
类执行计划任务。基本上一个计划任务执行的流程就完成了。
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 |