quartz简介
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.2.3。
quartz是一个任务调度系统,当应用程序需要天自动定时的完成一些任务的时候,quartz是首选,当然这些也可以使用timer(定时器)来实现。
quartz核心介绍
使用quartz的一些核心类的介绍:
- Trigger:用来触发任务的触发器
- Job:任务接口,需要执行的任务类实现这个接口的execute方法,Trigger按照指定的规则触发后会调用Job的execute方法
- SimpleScheduleBuilder:创建普通的触发规则,例如每隔多少时间触发一次任务
- CronScheduleBuilder:一般如果触发的规则比较复杂的话应该使用这个(注:这个类和上面的SimpleScheduleBuilder都是用来创建真正的规则的,他们并不是直接使用)
- JobDetail:上面的Job类将被它使用
- Scheduler:任务调度器,将Trigger和JobDetail绑定,调用Scheduler.start()方法之后,就会按照Trigger定义的规则触发Job了
- SchedulerFactory:工厂类,使用它的getScheduler()方法可以得到Scheduler对象
使用的CronScheduleBuidler的时间配置链接:
使用quartz的一些例子
下面我附上一篇官方demo里面的例子
package org.quartz.examples.example12;
//注意
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This example is a client program that will remotely
* talk to the scheduler to schedule a job. In this
* example, we will need to use the JDBC Job Store. The
* client will connect to the JDBC Job Store remotely to
* schedule the job.
*
* @author James House, Bill Kratzer
*/
public class RemoteClientExample {
public void run() throws Exception {
Logger log = LoggerFactory.getLogger(RemoteClientExample.class);
// First we must get a reference to a scheduler
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
// define the job and ask it to run
JobDetail job = newJob(SimpleJob.class)
.withIdentity("remotelyAddedJob", "default")
.build();
JobDataMap map = job.getJobDataMap();
map.put("msg", "Your remotely added job has executed!");
Trigger trigger = newTrigger()
.withIdentity("remotelyAddedTrigger", "default")
.forJob(job.getKey())
.withSchedule(cronSchedule("/5 * * ? * *"))
.build();
// schedule the job
sched.scheduleJob(job, trigger);
log.info("Remote job scheduled.");
}
public static void main(String[] args) throws Exception {
RemoteClientExample example = new RemoteClientExample();
example.run();
}
}
注:上面的例子有一个大坑,上面的导包语句使用静态导包,即:import static,如:
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
上面是静态导包语句,所在代码里面可以直接使用TriggerBuilder的newTrigger()静态方法,如果没有静态导包的话,那么直接复制官方demo的例子将报错
下面是SimpleJob类:
package org.quartz.examples.example12;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
/**
* <p>
* A dumb implementation of Job, for unittesting purposes.
* </p>
*
* @author James House
*/
public class SimpleJob implements Job {
public static final String MESSAGE = "msg";
private static Logger _log = LoggerFactory.getLogger(SimpleJob.class);
/**
* Quartz requires a public empty constructor so that the
* scheduler can instantiate the class whenever it needs.
*/
public SimpleJob() {
}
/**
* <p>
* Called by the <code>{@link org.quartz.Scheduler}</code> when a
* <code>{@link org.quartz.Trigger}</code> fires that is associated with
* the <code>Job</code>.
* </p>
*
* @throws JobExecutionException
* if there is an exception while executing the job.
*/
public void execute(JobExecutionContext context)
throws JobExecutionException {
// This job simply prints out its job name and the
// date and time that it is running
JobKey jobKey = context.getJobDetail().getKey();
String message = (String) context.getJobDetail().getJobDataMap().get(MESSAGE);
_log.info("SimpleJob: " + jobKey + " executing at " + new Date());
_log.info("SimpleJob: msg: " + message);
}
}
javaweb项目中使用quartz的例子
InitializerQuartzServlet类:
public class InitializerQuartzServlet extends HttpServlet{
private StdSchedulerFactory schedFact = null;
private Scheduler scheduler = null;
@Override
public void init(ServletConfig cfg) throws javax.servlet.ServletException {
super.init(cfg);
try {
schedFact = new StdSchedulerFactory();
scheduler = schedFact.getScheduler();
JobDetail jobDetail = JobBuilder.newJob(GenerateDailyDataJob.class).withIdentity("dailyDataJob").build();
.repeatForever()).startNow().build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey("dailyTrigger", "dailyTriggerGroup"))
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 11 * * ?")).build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
try {
//
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
GenerateDailyDataJob类:
public class GenerateDailyDataJob implements Job{
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("hello, world!");
}
}
因为实在web项目中使用,而且是每天上午11点就触发这个任务,所以需要将InitializerQuartzServlet
这个Servlet跟随容器一起启动,所以在web.xml中要配置:
<servlet>
<servlet-name>InitializerQuartzServlet</servlet-name>
<servlet-class>
com.weixin.util.InitializerQuartzServlet
</servlet-class>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<!-- 加载及启动定时任务 true -->
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
<!-- 启动延迟时间 60秒 -->
<init-param>
<param-name>start-delay-seconds</param-name>
<param-value>60</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
quartz使用中的问题
某次在使用quartz的时候,会触发多次job,也就是本来应该只执行一次job的时候执行了多次,后来在网上看到,quartz不会跟随着tomcat关闭而关闭,最后导致的结果是启动了多少次就开启了多少个quartz任务(很有可能是我没调用Scheduler.shutdown()方法),现在我在InitializerQuartzServlet
的destroy声明周期中调用了Scheduler.shutdown()方法,旨在tomcat容器关闭之后会关闭掉Job任务