Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。
简单的说Quartz就是一个定时任务,可以设定需要的时间或者时间间隔让它定时执行。如果是一般简单的任务调度,借助java本身的 java.util.Timer 就可以实现。只不过Quartz的功能更加的强大,配置更加的灵活,还可以集群等。
看看Quartz怎么和spring配合使用吧:
一般一个简单任务只需要以下几个包:commons-beanutils.jar、commons-collections.jar、commons-logging.jar、commons-digester.jar、quartz.jar即可。(可以到网上下载)
如果还需要其他比较特殊的功能,那么对照一下下面的。(学识浅薄,不一定全部都对)
名称 | 必须/备注 | |
activation.jar | 主要是 JavaMail 要用到 | |
commons-beanutils.jar | 是 | |
commons-collections.jar | 是 | |
commons-dbcp-1.1.jar | 是,假如用到数据库作为作业存 | |
commons-digester.jar | 是 | 假如你使用了某些插件,就需要它 |
commons-logging.jar | 是 | |
commons-pool-1.1.jar | ||
javamail.jar | 发送 e-mail 用 | |
jdbc2_0-stdext.jar | 是,假如用到数据库作为作业存储 | |
jta.jar | 是,假如用到数据库作为作业存储 | |
quartz.jar | 是 | Quart 框架核心包 |
servlet.jar | 假如使用了Servlet 容器,但容器中应该存在 | |
log4j.jar | 是,日志 |
使用Quartz前需要添加一个properties文件,用来配置Quartz的相关属性,看看:
quartz.properties
# 配置主调度器属性
org.quartz.scheduler.instanceName = QuartzScheduler
org.quartz.scheduler.instanceId = AUTO
# 配置线程池
# Quartz线程池的实现类
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 线程池的线程数量
org.quartz.threadPool.threadCount = 1
# 线程池里线程的优先级
org.quartz.threadPool.threadPriority = 5
# 配置作业存储
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class =org.quartz.simpl.RAMJobStore
#介绍一些配置信息,好记性不如烂笔头
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# ===========================================================================
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
#org.quartz.scheduler.instanceName: DefaultQuartzScheduler
#org.quartz.scheduler.instanceid:AUTO
#org.quartz.scheduler.rmi.export: false
#org.quartz.scheduler.rmi.proxy: false
#org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
# ===========================================================================
# Configure ThreadPool 线程池属性
# ===========================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
#org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
#org.quartz.threadPool.threadCount: 10
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
#org.quartz.threadPool.threadPriority: 5
#设置SimpleThreadPool的一些属性
#设置是否为守护线程
#org.quartz.threadpool.makethreadsdaemons = false
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#org.quartz.threadpool.threadsinheritgroupofinitializingthread=false
#线程前缀默认值是:[Scheduler Name]_Worker
#org.quartz.threadpool.threadnameprefix=swhJobThead;
# 配置全局监听(TriggerListener,JobListener) 则应用程序可以接收和执行 预定的事件通知
# ===========================================================================
# Configuring a Global TriggerListener 配置全局的Trigger监听器
# MyTriggerListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass
#org.quartz.triggerListener.NAME.propName = propValue
#org.quartz.triggerListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configuring a Global JobListener 配置全局的Job监听器
# MyJobListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass
#org.quartz.jobListener.NAME.propName = propValue
#org.quartz.jobListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configure JobStore 存储调度信息(工作,触发器和日历等)
# ===========================================================================
# 信息保存时间 默认值60秒
#org.quartz.jobStore.misfireThreshold: 60000
#保存job和Trigger的状态信息到内存中的类
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# ===========================================================================
# Configure SchedulerPlugins 插件属性 配置
# ===========================================================================
# 自定义插件
#org.quartz.plugin.NAME.class = com.swh.MyPluginClass
#org.quartz.plugin.NAME.propName = propValue
#org.quartz.plugin.NAME.prop2Name = prop2Value
#配置trigger执行历史日志(可以看到类的文档和参数列表)
#org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
#org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}
#org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
#配置job调度插件 quartz_jobs(jobs and triggers内容)的XML文档
#加载 Job 和 Trigger 信息的类 (1.8之前用:org.quartz.plugins.xml.JobInitializationPlugin)
#org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
#指定存放调度器(Job 和 Trigger)信息的xml文件,默认是classpath下quartz_jobs.xml
#org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml
#org.quartz.plugin.jobInitializer.overWriteExistingJobs = false
#org.quartz.plugin.jobInitializer.failOnFileNotFound = true
#自动扫描任务单并发现改动的时间间隔,单位为秒
#org.quartz.plugin.jobInitializer.scanInterval = 10
#覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况
#org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
# ===========================================================================
# Sample configuration of ShutdownHookPlugin ShutdownHookPlugin插件的配置样例
# ===========================================================================
#org.quartz.plugin.shutdownhook.class = \org.quartz.plugins.management.ShutdownHookPlugin
#org.quartz.plugin.shutdownhook.cleanShutdown = true
#
# Configure RMI Settings 远程服务调用配置
#
#如果你想quartz-scheduler出口本身通过RMI作为服务器,然后设置“出口”标志true(默认值为false)。
#org.quartz.scheduler.rmi.export = false
#主机上rmi注册表(默认值localhost)
#org.quartz.scheduler.rmi.registryhost = localhost
#注册监听端口号(默认值1099)
#org.quartz.scheduler.rmi.registryport = 1099
#创建rmi注册,false/never:如果你已经有一个在运行或不想进行创建注册
# true/as_needed:第一次尝试使用现有的注册,然后再回来进行创建
# always:先进行创建一个注册,然后再使用回来使用注册
#org.quartz.scheduler.rmi.createregistry = never
#Quartz Scheduler服务端端口,默认是随机分配RMI注册表
#org.quartz.scheduler.rmi.serverport = 1098
#true:链接远程服务调度(客户端),这个也要指定registryhost和registryport,默认为false
# 如果export和proxy同时指定为true,则export的设置将被忽略
#org.quartz.scheduler.rmi.proxy = false
然后我们需要添加一个spring的配置文件,然后把它import到spring的主配置文件里面:
spring-quartz.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- 要调用的工作类,就是你自己创建的类 -->
<bean id="ehCacheQuartzJob" class="com.im.socket.quartz.EhCacheQuartzJob" />
<!-- 定义调用对象和调用对象的方法 -->
<bean id="ehCacheQuartzJobTask"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 需要调用的类 -->
<property name="targetObject">
<ref bean="ehCacheQuartzJob" />
</property>
<!-- 需要调用类中的方法 -->
<property name="targetMethod">
<value>ehCacheWork</value>
</property>
</bean>
<!-- 定义触发时间 -->
<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail">
<ref bean="ehCacheQuartzJobTask" />
</property>
<!-- cron表达式,这个可以配置任务调度的时间,待会看下面的介绍 -->
<property name="cronExpression">
<value>5/60 * * * * ?</value>
</property>
</bean>
<!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 -->
<bean id="startQuertz" lazy-init="false" autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 读取配置 -->
<property name="configLocation" value="classpath:quartz.properties" />
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
</beans>
看看需要调用的任务类:
package com.im.socket.quartz;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.im.socket.general.Constants;
import com.im.socket.netty.tcp.MessageUtil;
import com.im.socket.protobuf.MessageOuterClass.Message;
import com.im.socket.utils.EHCacheUtil;
import com.im.socket.utils.RedisUtil;
import com.im.utils.DateTimeUtil;
/**
* 任务调度类
*
* @author kokJuis
* @version 1.0
* @date 2016-9-28
*/
public class EhCacheQuartzJob {
/**
* 任务调度的方法
*
* @author kokJuis
* @version 1.0
* @date 2016-9-28
*/
public void ehCacheWork() {
//业务逻辑
}
}
好了,一般 Quartz使用就是这么简单。看看Cron表达式怎么配置吧:
位置 | 含义 | 允许的特殊字符 |
1 | 秒(0~59) | , - * / |
2 | 分(0~59) | , - * / |
3 | 小时(0~24) | , - * / |
4 | 日期(1~31) | , - * / ? L W C |
5 | 月(JAN~DEC或1~12) | , - * / |
6 | 星期(SUN~SAT或1~7) | , - * / ? L C # |
7 | 年(可选,1970~2099),若为空,表示全部时间范围 | , - * / |
特殊字符 | 说明 |
* | 通配符,任意值 |
? | 无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查 |
- | 范围。e.g.小时部分10-12表示10:00,11:00, 12:00 |
, | 列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON、TUE和WED |
/ | 增量。表示一个值的增量,e.g.分钟域中0/1表示从0开始,每次增加1min |
L | 表示Last。它在日期和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中,它永远是7(星期六)。当你希望使用星期中某一天时,L字符非常有用。e.g.星期域中6L表示每一个月的最后一个星期五 |
W | 在本月内离当天最近的工作日触发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离是0;所谓本月内指的是不能跨月取到最近工作日,即使前/后月份的最后一天/第一天确实满足最近工作日。e.g. LW表示本月的最后一个工作日触发,W强烈依赖月份。 |
# | 表示该月的第几个星期,e.g. 1#2表示每一个月的第一个星期一 |
C | 日历值。日期值是根据一个给定的日历计算出来的。在日期域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。例如在一个星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五) |