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任務