之前的项目里有使用定时器,每隔一段时间去 MQ 服务器拉取新的消息。
使用的是Java 自身的 TimerTask 以及监听器实现的,因为项目需求变更,回头查看代码时,发现原来的实现不是很合理(一个Task里面做了多项操作),就找到Quarts这个开源框架了。
首先,看看原来使用Java提供的TimerTask 来实现定时触发的方法:
1.新建一个继承自java.util.TimerTask的类,重写其run()方法,这就是我们要定时执行的任务了:
import java.util.TimerTask;
public class GetMessageTask extends TimerTask {
@Override
public void run() {
System.out.println("Ho ho, GetMessageTask is running @ "
+ new java.util.Date());
}
}
2.新建一个定时器类,在这个类中定义一个java.util.Timer类型的属性用来定义我们的执行任务的开始时间以及,时间间隔:
public class GetMessageTimer {
java.util.Timer timer;
public void startTimer() {
timer = new java.util.Timer();
/**
* 系统启动1分钟后开始执行任务
*/
java.util.GregorianCalendar gc = new java.util.GregorianCalendar();
gc.setTime(new java.util.Date());
gc.add(java.util.Calendar.MINUTE, 1);
System.out.println("定时器 @ " + new java.util.Date() + "开启了!");
/**
* 每30000毫秒执行一次取数任务
*/
timer.schedule(new GetMessageTask(), gc.getTime(), 30000);
}
public void stopTimer() {
if (timer != null)
timer.cancel();
System.out.println("定时器 @ " + new java.util.Date() + "关闭了!");
}
}
3.新建一个监听器,用于应用部署时,启动我们的定时器:
public class GetMessageListener implements ServletContextListener {
GetMessageTimer timer = new GetMessageTimer();
@Override
public void contextDestroyed(ServletContextEvent sce) {
timer.stopTimer();
}
@Override
public void contextInitialized(ServletContextEvent sce) {
timer.startTimer();
}
}
4.在web.xml中配置监听器:
定时取数
com.abc.web.timertask.GetMessageListener
index.jsp
这样我们就完成了,部署至Web 容器,查看控制台输出如下图:
由图所示,定时器开启1分钟以后,我们的任务每隔30秒执行一次。
接下来,我们看一下,怎样使用 Quartz 来实现上面的功能。
1.首先下载 Quartz 不必多说了。
Quartz官网:http://quartz-scheduler.org/
我下的版本为2.1.3
2.新建 java web app,将所需jar包导入项目:
3.我们是要在web app中使用quartz,查看官网文档http://quartz-scheduler.org/documentation/quartz-2.1.x/cookbook/ServletInitScheduler,我们可以看出,可以使用2种方法来启动quartz,这里我们使用servlert的方式来启动,修改web.xml如下:
QuartzInitializer
org.quartz.ee.servlet.QuartzInitializerServlet
shutdown-on-unload
true
start-scheduler-on-load
true
start-delay-seconds
60
1
index.jsp
4.查看相关文档,我们要先创建我们要执行的Job:
public class GetMessageJob implements Job {
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello, GetMessageJob is Executing @ "
+ new java.util.Date());
}
}
5.接着我们要新建Trigger,来告诉Schedule神马时候执Job,因为是测试没有集成其他框架,所以我就想到了quartz自带的QuartzInitializarServlet,这里我们改写这个Servlet。这个Servlet的源码,可以在下载的文档里找到,下面是我改写的Servlet:
public class InitializerQuartzServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public static final String QUARTZ_FACTORY_KEY = "org.quartz.impl.StdSchedulerFactory.KEY";
private boolean performShutdown = true;
private boolean waitOnShutdown = false;
private transient Scheduler scheduler = null;
@Override
public void init(ServletConfig cfg) throws javax.servlet.ServletException {
super.init(cfg);
System.out
.println("Quartz Initializer Servlet 加载成功, initializing Scheduler...");
StdSchedulerFactory factory;
try {
String configFile = cfg.getInitParameter("config-file");
String shutdownPref = cfg.getInitParameter("shutdown-on-unload");
if (shutdownPref != null) {
performShutdown = Boolean.valueOf(shutdownPref).booleanValue();
}
String shutdownWaitPref = cfg.getInitParameter("wait-on-shutdown");
if (shutdownPref != null) {
waitOnShutdown = Boolean.valueOf(shutdownWaitPref)
.booleanValue();
}
factory = getSchedulerFactory(configFile);
scheduler = factory.getScheduler();
String startOnLoad = cfg
.getInitParameter("start-scheduler-on-load");
int startDelay = 0;
String startDelayS = cfg.getInitParameter("start-delay-seconds");
try {
if (startDelayS != null && startDelayS.trim().length() > 0)
startDelay = Integer.parseInt(startDelayS);
} catch (Exception e) {
log(
"Cannot parse value of 'start-delay-seconds' to an integer: "
+ startDelayS + ", defaulting to 5 seconds.", e);
startDelay = 5;
}
/*
* 告诉scheduler要执行的任务,以及执行间隔时间,这里是30秒
*/
JobDetail getMessageJob = newJob(GetMessageJob.class).withIdentity(
"getDetailsJob", "group1").build();
Trigger getMessageTrigger = newTrigger().withIdentity(
"getDetailsTrigger", "group1").startNow().withSchedule(
simpleSchedule().withIntervalInSeconds(30).repeatForever())
.build();
scheduler.scheduleJob(getMessageJob, getMessageTrigger);
if (startOnLoad == null
|| (Boolean.valueOf(startOnLoad).booleanValue())) {
if (startDelay <= 0) {
// Start now
scheduler.start();
System.out.println("Scheduler has been started...");
} else {
// Start delayed
scheduler.startDelayed(startDelay);
System.out.println("Scheduler will start in " + startDelay
+ " seconds.");
}
} else {
System.out
.println("Scheduler has not been started. Use scheduler.start()");
}
String factoryKey = cfg
.getInitParameter("servlet-context-factory-key");
if (factoryKey == null) {
factoryKey = QUARTZ_FACTORY_KEY;
}
System.out
.println("Storing the Quartz Scheduler Factory in the servlet context at key: "
+ factoryKey);
cfg.getServletContext().setAttribute(factoryKey, factory);
String servletCtxtKey = cfg
.getInitParameter("scheduler-context-servlet-context-key");
if (servletCtxtKey != null) {
System.out
.println("Storing the ServletContext in the scheduler context at key: "
+ servletCtxtKey);
scheduler.getContext().put(servletCtxtKey,
cfg.getServletContext());
}
} catch (Exception e) {
System.out.println("Quartz Scheduler 初始化失败: "
+ e.toString());
throw new ServletException(e);
}
}
protected StdSchedulerFactory getSchedulerFactory(String configFile)
throws SchedulerException {
StdSchedulerFactory factory;
// get Properties
if (configFile != null) {
factory = new StdSchedulerFactory(configFile);
} else {
factory = new StdSchedulerFactory();
}
return factory;
}
@Override
public void destroy() {
if (!performShutdown) {
return;
}
try {
if (scheduler != null) {
scheduler.shutdown(waitOnShutdown);
}
} catch (Exception e) {
System.out.println("Quartz Scheduler 停止失败: "
+ e.toString());
e.printStackTrace();
}
System.out.println("Quartz Scheduler 停止了.");
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
}
org.quartz.scheduler.instanceName: ExampleScheduler
org.quartz.threadPool.threadCount: 3
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.jobStore.class:org.quartz.simpl.RAMJobStore
上图所示,定时器在应用部署1分钟后开始启动,任务每隔30秒执行一次。
更高级的使用Quartz的方法,请大家参考cookbook。