
Quartz也常用在Web应用中,常见的是交由Spring托管的形式,但这里并非介绍这个。如果你的很老的一个项目没有使用Spring呢? 这里我们介绍Quartz在Web应用中单独使用的场景。
对于定时任务来讲,一般来说,Web应用启动时,应注册已经确定的定时任务;一些动态的、未确定触发时间的定时任务,后续可通过静态的Scheduler注册。
这里使用监听器在应用启动时注册,需要在web.xml注册这个监听器,在关闭Web应用时,也要相应的注销定时任务。
maven工程

pom.xml中添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.artisangroupId>
<artifactId>quartzInWebartifactId>
<packaging>warpackaging>
<version>0.0.1-SNAPSHOTversion>
<name>quartzInWeb Maven Webappname>
<url>http://maven.apache.orgurl>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
<version>2.2.3version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.21version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.21version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.1.7version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.1.7version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
dependencies>
<build>
<finalName>quartzInWebfinalName>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.1version>
<configuration>
<source>1.7source>
<target>1.7target>
configuration>
plugin>
plugins>
build>
project><configuration debug="true">
<property name="APP_NAME" value="logtest" />
<property name="LOG_HOME" value="${log.dir:-logs}/${APP_NAME}" />
<property name="ENCODER_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n" />
<contextName>${APP_NAME}contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>${ENCODER_PATTERN}Pattern>
encoder>
appender>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/output.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>7maxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${ENCODER_PATTERN}pattern>
encoder>
appender>
<appender name="ERROR_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>7maxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${ENCODER_PATTERN}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARNlevel>
filter>
appender>
<appender name="SYNC_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/sync.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>7maxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${ENCODER_PATTERN}pattern>
encoder>
appender>
<logger name="log.sync" level="DEBUG" addtivity="true">
<appender-ref ref="SYNC_FILE" />
logger>
<root>
<level value="DEBUG" />
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
<appender-ref ref="ERROR_FILE" />
root>
configuration>package com.artisan.quartz;
import static org.quartz.JobBuilder.newJob;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApplicationContextListener implements ServletContextListener {
private Logger logger = LoggerFactory
.getLogger(ApplicationContextListener.class);
public static Scheduler scheduler = null;
public void contextInitialized(ServletContextEvent servletContextEvent) {
logger.info("Web应用开始...");
/* 注册定时任务 */
try {
// 获取Scheduler实例
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
// 具体任务
JobDetail job = 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);
logger.info("调度器开始注册:The scheduler register...");
} catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
}
public void contextDestroyed(ServletContextEvent sce) {
logger.info("Web应用停止...");
/* 注销定时任务 */
try {
// 关闭Scheduler
scheduler.shutdown();
logger.info("调度器已关闭:The scheduler shutdown...");
} catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
}
}假设我们有一个明确的任务,在初始化监听器的时候就启动执行,如下
package com.artisan.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloJob implements Job {
private Logger logger = LoggerFactory.getLogger(HelloJob.class);
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello Job");
// 此任务仅打印日志便于调试、观察
System.out.println(this.getClass().getSimpleName() + " trigger...");
logger.debug(this.getClass().getSimpleName() + " trigger...");
}
}<?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.artisan.quartz.ApplicationContextListener</listener-class>
</listener>
</web-app>由于我们使用的JDK1.7 ,我们用的tomcat,这里tomcat的版本需要为8.0

关键日志如下:

如果我们Eclipse或者Spring tool suit中调试,无法看到contextDestroyed方法的执行。
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();repeatForever()方法,这个方法的意思表示永远执行,当然我们也可以自定义重复执行的次数,使用withRepeatCount(10)方法,10表示执行了10次