Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现。作为企业级别的定时任务调度,Quartz不仅仅拥有强大的调度功能,也支持各种灵活的应用方式,并同时支持分布式和集群能力。
基本使用
Quartz的使用非常简单,首先在POM里面加入引用
<!-- Quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
然后在项目初始化的时候启动它
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
我们再定义一下定时任务要做啥
public class MyJob implements org.quartz.Job {
public MyJob() {
}
public void execute(JobExecutionContext context) throws JobExecutionException {
System.err.println("Hello World! MyJob is executing.");
}
}
最后我们就可以增加一个定时任务了
// 定义一个要执行的Job
JobDetail job = newJob(MyJob.class)
.withIdentity("job1", "group1")
.build();
// 定义一个间隔40秒运行的Trigger
Trigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build();
// 告诉Quartz去用trigger安排启动job
scheduler.scheduleJob(job, trigger);
是不是很简单,其实还有很多用法可以直接取官网上看查阅一下文档,就可以快速实现你的功能了。
http://www.quartz-scheduler.org/documentation/quartz-2.2.x/quick-start.html
提高篇
Quartz在启动过程中会默认读取classpath下的quartz.preperties文件完成一些初始化工作。在这里我们主要谈的是org.quartz.jobStore.class这个配置项。
Quartz官方支持三种数据存储方式
-
RAMJobStore
RAMJobStore是默认的数据存储方式,其把数据存在本地内存中,官方宣称这是最有效率的方式(在本地内存当然快啦)。但是在宕机或者重启的时候数据就会丢失。
//配置方式 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
-
JDBCJobStore
JDBCJobStore终于把数据给持久化起来了,这个也是使用最广泛的数据存储方式。在于Spring集成后都不需要自己再配置一遍数据库连接了。建表脚本在官方包里面可以找到(http://www.quartz-scheduler.org/downloads/)
//配置方式 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.dataSource = myDS
-
TerracottaJobStore
在Quartz被Software AG收购后免不了要夹带一些私货。这个就是专门给Terracotta配置的。我也就懒得讲了,大家网上搜搜吧。
说了这么多,其实都是Quartz的标准用法。在使用实践中因为各种原因导致没有办法使用官方提供的三种数据存储方式。所以只有自己动手丰衣足食,开辟新的玩法了。
进阶篇 --- MongoDB
在使用的时候我们会发现Quartz的建表脚本和公司idb不怎么兼容,尝试找过DBA,但是他们也不愿意为单独一个项目做特殊处理。这个时候我们就将视线投入到其他存储方式上了,首先祭出的就是MongoDB。
首先在POM里面引入第三方库
<dependency>
<groupId>com.novemberain</groupId>
<artifactId>quartz-mongodb</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.2.2</version>
</dependency>
然后就和JDBCJobStore一样,在quartz.preperties中添加链接配置
org.quartz.jobStore.class=com.novemberain.quartz.mongodb.MongoDBJobStore
org.quartz.jobStore.mongoUri=${mongo.hostName}
org.quartz.jobStore.dbName=quartz
org.quartz.jobStore.collectionPrefix=mycol
org.quartz.threadPool.threadCount=1
如果要启动集群模式的话还需要加入下面的配置
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.jobStore.isClustered = true
进阶篇 --- Redis
还有一种情况下你会发现没有MongoDB可以使用。环绕四周,还有Redis在旁边。看看内存刑的KV Strore,想想它也可以被持久化到磁盘,于是咬咬牙也就用上了。不过遗憾的是受限于Redis,Quartz不能全功能发挥出来。主要的限制有下面几点
- 只支持SimpleTrigger和CronTrigger
- 对GroupMatcher来说,只支持StringOperatorName.EQUALS操作
- org.quartz.scheduler.instanceName是不支持的,所以你得自己去维护trigger_group_name:trigger_name和job_group_name:job_name
- 没有办法使用transaction
- JobDataMap的内容是作为String存储和返回
- 定时任务没有优先级概念,只在设定的时间内启动
不过瑕不掩瑜(其实是我们也用不上这些高级功能),我们还是可以克服困难愉快的用上Quartz的。首先还是要引入三方包
<dependency>
<groupId>net.joelinn</groupId>
<artifactId>quartz-redis-jobstore</artifactId>
<version>1.1.3</version>
</dependency>
<!-- Redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
其次还是配置一下quartz.preperties
org.quartz.jobStore.class = net.joelinn.quartz.jobstore.RedisJobStore
org.quartz.jobStore.host = ${redis.hostName}
org.quartz.jobStore.password = ${redis.password}
org.quartz.jobStore.port = ${redis.port}
org.quartz.jobStore.database: ${redis.database.quartz}
最后别忘了配置你的Jedis
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}"></property>
<property name="maxIdle" value="${redis.pool.maxIdle}"></property>
<property name="minIdle" value="${redis.pool.minIdle}"></property>
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}"></property>
<property name="minEvictableIdleTimeMillis" value="${redis.pool.minEvictableIdleTimeMillis}"></property>
<property name="numTestsPerEvictionRun" value="${redis.pool.numTestsPerEvictionRun}"></property>
<property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}"></property>
<property name="testOnBorrow" value="true"></property>
<property name="testOnReturn" value="true"></property>
<property name="testWhileIdle" value="true"></property>
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.hostName}"/>
<property name="port" value="${redis.port}"/>
<property name="timeout" value="${redis.timeout}"/>
<property name="database" value="${redis.database.crowd}"/>
<property name="password" value="${redis.password}"/>
<property name="usePool" value="true"/>
<property name="poolConfig" ref="jedisPoolConfig"/>
</bean>
参考链接
- http://www.quartz-scheduler.org/
- https://github.com/michaelklishin/quartz-mongodb
- https://github.com/jlinn/quartz-redis-jobstore