quartz 是java 领域中应用最广泛的一个定时任务调度框架, 支持两种存储方式:基于内存存储和基于数据库存储. 同城在企业开发中都是结合spring使用, 直接按指定规则配置即可. 但是笔者认为, 要想对quartz 有个相对比较深入的了解, 还是应该搭建一个JavaSE 环境来进行学习和测试. quartz 的开发流程:
- 创建调度器工厂
- 加载配置文件(如果使用默认配置文件名, 则可以省略)
- 获取调度器
- 创建定时任务
- 创建触发器(可以是SimpleTrigger 和 CronTrigger)
- 将定时任务添加到调度器中
- 启动调度器
1. 项目搭建
笔者习惯于使用maven 开发项目, 因此首先创建一个maven 项目.
1.1 引入maven 依赖
- quartz 只需要引入一个核心依赖 quartz 即可.
- quartz 默认使用slf4j 输出日志, 但是笔者习惯于使用logback, 因此直接替换了logback 的包.
- 笔者使用junit 单元测试进行测试
<!-- 相关版本号 -->
<properties>
<quartz.version>2.2.3</quartz.version>
<slf4j.api.version>1.7.25</slf4j.api.version>
<logback.version>1.2.3</logback.version>
<junit.version>4.12</junit.version>
</properties>
<!-- 相关依赖 -->
<dependencies>
<!-- 引入quartz 核心包 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
</dependency>
<!-- 集成日志环境 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.api.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- 添加单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
1.2 创建quartz 配置文件
- quartz 默认加载类路径下的quartz.propeties 文件作为quartz 的配置文件, 此文件中可以自定义quartz的一些运行参数.
- 默认情况下如果找不到quartz.preoperties文件, quartz 会加载自身jar保重的配置文件. 不过笔者还是推荐使用自定义的配置文件.
- 配置文件的默认名称为quartz.properties,不过可以修改. 笔者修改为quartz-ram.properties.
quartz-ram.properties
# 调度器实例名称
org.quartz.scheduler.instanceName = quartz-scheduler-ram
# 定时任务信息存储方式: 内存
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
# 定时任务线程数
org.quartz.threadPool.threadCount = 3
1.3 创建日志配置文件
logback 需要在类路径下创建logback.xml配置文件.
logback.xml
<?xml version="1.0"?>
<configuration debug="false">
<!-- 应用名称 -->
<contextName>learn-quartz</contextName>
<!-- 输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 定义日志输出格式 -->
<pattern>[%d{yyyy-MM-dd HH:mm:ss:SSS}][%thread][%thread][%-5level][%logger{36}]-%msg%n</pattern>
</encoder>
</appender>
<!-- 配置根logger -->
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
2. 开发定时任务
2.1 创建定时任务类
quartz 规定每一个要执行的定时任务都需要继承org.quartz.Job 接口, 病实现execute 方法. 当定时任务触发时, quartz 会新实例化一个Job实例, 然后调用其execute 方法.
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloJob implements Job {
private static Logger logger = LoggerFactory.getLogger(HelloJob.class);
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Trigger trigger = jobExecutionContext.getTrigger();
logger.info("hello,quartz! this:{}, job:{}, trigger:{}, preFire:{}, nextFire:{},",
this,jobExecutionContext.getJobDetail().getKey(), trigger.getKey(),
toString(trigger.getPreviousFireTime()), toString(trigger.getNextFireTime()));
}
// 格式化日期
private String toString(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
return simpleDateFormat.format(date);
}
}
2.2 创建测试类
quartz的触发器有两种, 一种是SimpleTrigger, 用于触发重复1次或以固定时间重复N次的定时任务; 另一种是CronTrigger, 用于触发按日历来执行的定时任务. 笔者针对于这两种触发器, 写了两个入门demo.
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.zongf.learn.quartz.l01.job.HelloJob;
/**
* @Description: 测试环境集成
* @author: zongf
* @date: 2019-03-27 10:58
*/
public class Test01 {
private SchedulerFactory schedulerFactory;
private Scheduler scheduler;
// 测试用例启动时, 初始化调度工厂和调度器
@Before
public void setUp() throws SchedulerException {
// 1. 创建调度工厂
schedulerFactory = new StdSchedulerFactory();
// 2. 默认加载类路径下quartz.properties配置文件, 笔者指定配置文件
((StdSchedulerFactory) schedulerFactory).initialize("quartz-ram.properties");
// 3. 获取调度器
scheduler = schedulerFactory.getScheduler();
}
// 测试用例完成时, 线程休眠, 否则进行就直接结束了
@After
public void tearDown() throws InterruptedException {
Thread.sleep(Integer.MAX_VALUE);
}
// 测试简单触发器
@Test
public void scheduSimpleTrigger() throws SchedulerException {
// 4. 创建定时任务
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "group1")
.build();
// 5. 创建简单触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
// 6. 将定时任务添加到调度队列中
scheduler.scheduleJob(job, trigger);
// 7. 启动调度器
scheduler.start();
}
// 测试cron 触发器
@Test
public void test_CronTrigger() throws SchedulerException {
// 4. 创建定时任务
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "group1")
.build();
// 6. 创建cron触发器, 每5秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))
.build();
// 7. 将定时任务添加到调度队列中
scheduler.scheduleJob(job, trigger);
// 8. 启动调度器
scheduler.start();
}
}
2.3 测试输出结果
从控制台输出可以看出, 每次执行的job实例都不相同, 这一点是很重要的.
[2019-03-28 17:06:10:645]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@b25e99f, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:10.000, nextFire:2019-03-28 17:06:15.000,
[2019-03-28 17:06:15:003]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@6d5a007, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:15.000, nextFire:2019-03-28 17:06:20.000,
[2019-03-28 17:06:20:002]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@1e9e39a8, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:20.000, nextFire:2019-03-28 17:06:25.000,
[2019-03-28 17:06:25:003]-hello,quartz! this:org.zongf.learn.quartz.l01.job.HelloJob@2e0899d0, job:group1.myJob, trigger:group1.myTrigger, preFire:2019-03-28 17:06:25.000, nextFire:2019-03-28 17:06:30.000,
来源:https://blog.csdn.net/zongf0504/article/details/89241289