在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"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 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"> <!-- 加入自定义监听器 --> <listener> <listener-class>com.anson.listener.ApplicationContextListener</listener-class> </listener> </web-app>
把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次