非Spring下的Quartz
Quartz在Java构建的系统中,是十分常用的定时任务框架。
本文,记录、介绍Quartz的简单入门的单独搭建(此文入门学习Quartz为主,并非基于Spring托管形式)。
> 参考的优秀资料
Chapter 3: Logback configuration
> 版本说明
除了Quartz,还引入logback(为了看详细的日志嘛!)
> 简单的搭建
jar包的引入参考上述的pom文件。
quartz.properties,配置quartz的设置。
注,org.quartz.threadPool.threadCount,配置线程池的容量,即表示同时最多可运行的线程数量。在生产环境,此参数应根据实际情况配置。
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
logback.xml,日志框架logback的配置。这里只简单地配置了控制台和日志文件的输出哦(>_<)
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder
by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>D:/logs/quartz_task_application.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
HelloJob.java,具体执行的任务
package No01简单的定时任务;
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 {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
// 此任务仅打印日志便于调试、观察
this.logger.debug(this.getClass().getName() + " trigger...");
}
}
那么,在哪里定义“在什么时候执行什么任务呢?”
package No01简单的定时任务;
import java.util.concurrent.TimeUnit;
import org.quartz.JobBuilder;
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 Bootstrap {
private static Logger logger = LoggerFactory.getLogger(Bootstrap.class);
public static void main(String[] args) {
try {
// 获取Scheduler实例
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);
/* 为观察程序运行,此设置主程序睡眠3分钟才继续往下运行(因下一个步骤是“关闭Scheduler”) */
try {
TimeUnit.MINUTES.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 关闭Scheduler
scheduler.shutdown();
} catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
}
}
> 在Web应用中使用Quartz
Quartz也常用在Web应用中,常见的是交由Spring托管的形式,但这里并非介绍这个。这里介绍Quartz在Web应用中单独使用。
一般来说,Web应用启动时,应注册已经确定的定时任务;一些动态的、未确定触发时间的定时任务,后续可通过静态的Scheduler注册。
这里使用监听器在应用启动时注册,记得在web.xml注册这个监听器哦(>_<);在关闭Web应用时,也要相应的注销定时任务。
其他配置文件、Java类与上例子相同,这里只是注册定时任务的地方换成此监听器了。
package No02Web应用使用Quartz;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.quartz.JobBuilder;
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;
import No01简单的定时任务.HelloJob;
/**
* Application Lifecycle Listener implementation class AListener
*
*/
public class ApplicationContextListener implements ServletContextListener {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public static Scheduler scheduler = null;
@Override
public void contextInitialized(ServletContextEvent arg0) {
this.logger.info("The application start...");
/* 注册定时任务 */
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 arg0) {
this.logger.info("The application stop...");
/* 注销定时任务 */
try {
// 关闭Scheduler
scheduler.shutdown();
this.logger.info("The scheduler shutdown...");
} catch (SchedulerException se) {
logger.error(se.getMessage(), se);
}
}
}
<listener>
<listener-class>No02Web应用使用Quartz.ApplicationContextListener</listener-class>
</listener>
注,如果你在Eclipse中调试,可能发现无法看到contextDestroyed方法的执行,请注意用Stop方式(图一)关闭应用,而不是Terminate(图二)。
图一
图二
> 常用的Cron Schedule
相对于其他方式定义定时任务的触发时间,我们较常用Cron Schedule,小伙伴们也是吧?
Cron Schedule的使用
// 具体任务
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
// 触发时间点
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0 * * * * ? *");
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.withSchedule(cronScheduleBuilder).build();
// 交由Scheduler安排触发
scheduler.scheduleJob(job, trigger);
而Cron Expression的学习可参考下列优秀的文章: