在Web应用中使用Quartz
Quartz也常用在Web应用中,常见的是交由Spring托管的形式,但这里并非介绍这个。这里介绍Quartz在Web应用中单独使用。
一般来说,Web应用启动时,应注册已经确定的定时任务;一些动态的、未确定触发时间的定时任务,后续可通过静态的Scheduler注册。
这里使用监听器在应用启动时注册,记得在web.xml注册这个监听器哦;在关闭Web应用时,也要相应的注销定时任务。
其他配置文件、Java类与上例子相同,这里只是注册定时任务的地方换成此监听器了。package com.anson.listener;
import com.anson.example1.HelloJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 自定义一个应用监听器
*/
public class ApplicationContextListener implements ServletContextListener {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public static Scheduler scheduler = null;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
this.logger.info("Web应用开始...");
/* 注册定时任务 */
try {
// 获取Scheduler实例
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
// 具体任务
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
// 触发时间点
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).repeatForever();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.startNow().withSchedule(simpleScheduleBuilder).build();
// 交由Scheduler安排触发
scheduler.scheduleJob(job, trigger);
this.logger.info("调度器开始注册:The scheduler register...");
} catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
this.logger.info("Web应用停止...");
/* 注销定时任务 */
try {
// 关闭Scheduler
scheduler.shutdown();
this.logger.info("调度器已关闭:The scheduler shutdown...");
} catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
}
}
web.xml<?xml version="1.0" encoding="UTF-8"?>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
com.anson.listener.ApplicationContextListener
把Web项目在Tomcat中运行测试[INFO] 09 九月 06:19:56.121 下午 RMI TCP Connection(2)-127.0.0.1 [com.anson.listener.ApplicationContextListener]
Web应用开始...
[INFO] 09 九月 06:19:56.146 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.impl.StdSchedulerFactory]
Using default implementation for ThreadExecutor
[INFO] 09 九月 06:19:56.160 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.core.SchedulerSignalerImpl]
Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
[INFO] 09 九月 06:19:56.161 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.core.QuartzScheduler]
Quartz Scheduler v.2.2.3 created.
[INFO] 09 九月 06:19:56.161 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.simpl.RAMJobStore]
RAMJobStore initialized.
[INFO] 09 九月 06:19:56.162 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.core.QuartzScheduler]
Scheduler meta-data: Quartz Scheduler (v2.2.3) 'MyScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
[INFO] 09 九月 06:19:56.162 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler 'MyScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
[INFO] 09 九月 06:19:56.162 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler version: 2.2.3
[INFO] 09 九月 06:19:56.162 下午 RMI TCP Connection(2)-127.0.0.1 [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED started.
[INFO] 09 九月 06:19:56.168 下午 RMI TCP Connection(2)-127.0.0.1 [com.anson.listener.ApplicationContextListener]
调度器开始注册:The scheduler register...
Hello Job
[DEBUG] 09 九月 06:19:56.177 下午 MyScheduler_Worker-1 [com.anson.example1.HelloJob]
com.anson.example1.HelloJob trigger...
[2017-09-09 06:19:56,206] Artifact quartz_example:war exploded: Artifact is deployed successfully
[2017-09-09 06:19:56,206] Artifact quartz_example:war exploded: Deploy took 643 milliseconds
Hello Job
[DEBUG] 09 九月 06:20:01.168 下午 MyScheduler_Worker-2 [com.anson.example1.HelloJob]
com.anson.example1.HelloJob trigger...
09-Sep-2017 18:20:05.276 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/Users/liurenkui/myLibrary/apache-tomcat-8.5.15/webapps/manager]
09-Sep-2017 18:20:05.305 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/liurenkui/myLibrary/apache-tomcat-8.5.15/webapps/manager] has finished in [28] ms
Hello Job
[DEBUG] 09 九月 06:20:06.167 下午 MyScheduler_Worker-3 [com.anson.example1.HelloJob]
com.anson.example1.HelloJob trigger...
...
...
... 省略大部分web应用开启时的任务输出重复日志 ...
...
...
Hello Job
[DEBUG] 09 九月 06:23:26.170 下午 MyScheduler_Worker-1 [com.anson.example1.HelloJob]
com.anson.example1.HelloJob trigger...
/Users/liurenkui/myLibrary/apache-tomcat-8.5.15/bin/catalina.sh stop
09-Sep-2017 18:23:26.783 信息 [main] org.apache.catalina.core.StandardServer.await A valid shutdown command was received via the shutdown port. Stopping the Server instance.
09-Sep-2017 18:23:26.783 信息 [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
09-Sep-2017 18:23:26.840 信息 [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-nio-8009"]
09-Sep-2017 18:23:26.894 信息 [main] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
[INFO] 09 九月 06:23:26.900 下午 localhost-startStop-2 [com.anson.listener.ApplicationContextListener]
Web应用停止...
[INFO] 09 九月 06:23:26.900 下午 localhost-startStop-2 [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED shutting down.
[INFO] 09 九月 06:23:26.900 下午 localhost-startStop-2 [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED paused.
[INFO] 09 九月 06:23:26.900 下午 localhost-startStop-2 [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED shutdown complete.
[INFO] 09 九月 06:23:26.900 下午 localhost-startStop-2 [com.anson.listener.ApplicationContextListener]
调度器已关闭:The scheduler shutdown...
09-Sep-2017 18:23:26.911 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
09-Sep-2017 18:23:26.913 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-nio-8009"]
09-Sep-2017 18:23:26.917 信息 [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
09-Sep-2017 18:23:26.917 信息 [main] org.apache.c
注,如果你在Eclipse中调试,可能发现无法看到contextDestroyed方法的执行,请注意用Stop方式(图一)关闭应用,而不是Terminate(图二)。
图一
图二
如何不重复执行任务?
如果仔细阅读代码你会发现这块的代码// 触发时间点
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();
其中,最后结尾的是repeatForever()方法,这个方法的意思表示永远执行。
如果删除这行代码,那么job任务,也就只会执行一次,任务就挂起了,直到调度器关闭。
也可以自定义重复执行的次数,使用withRepeatCount(10)方法,10表示执行了10次