前言:
不久前需要定时任务,于是开始搞quartz。网上也有不少资料 ,但是大部分都是之前的版本。本文quartz版本2.1.7(也不是很新哈,随便找了个2.0版本以上的),spring版本3.2.17。
目标:
集群化quartz是quartz本身自带的功能,原理是将job和trigger持久化到数据库,各服务器节点之间通过数据库数据互相感知。本文将从quartz集群配置开始,完成从web端动态启停、添加和修改任务。
quartz下载:下载quartz (百度云-- 密码: k1mi)
主要文件:
解压下载的quartz,主要文件(夹)如下
1.初始化数据库表:
这个事情不用自己动手了,有现成的,拉出来用。解压路径/quartz-2.1.7/docs/dbTables。各种数据库都提供了.sql文件,找到自己用的数据库对应文件,接下来创建表就可以了。
2.导包、配置文件(pom解压文件中也有),其它包(例如spring)自行添加
在classpath下创建quartz.properties文件和JDBC的配置文件(这个文件就不用给了吧)。
#instancename值可以随意,用来在JDBCStore中作为唯一标识,但是所有实例节点必须都相同
org.quartz.scheduler.instanceName: MyScheduler
#instanceId 属性为 AUTO即可,基于主机名和时间戳来产生实例 ID。
org.quartz.scheduler.instanceId = AUTO
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 20
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#任务超时的控制,毫秒为单位。错过下次执行时间大于600毫秒就跳过中间这些任务,以当前时间为开始继续执行。
org.quartz.jobStore.misfireThreshold = 600
#org.quartz.jobStore.class属性为 JobStoreTX,将任务持久化到数据中。
#因为集群中节点依赖于数据库来传播 Scheduler实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。
#必须使用 JobStoreTX 或是 JobStoreCMT作为 Job存储;你不能在集群中使用 RAMJobStore。
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.maxMisfiresToHandleAtATime=10
#org.quartz.jobStore.isClustered 属性为 true,你就告诉了 Scheduler 实例要它参与到一个集群当中。
#这一属性会贯穿于调度框架的始终,用于修改集群环境中操作的默认行为。
org.quartz.jobStore.isClustered = true
#org.quartz.jobStore.clusterCheckinInterval 属性定义了Scheduler 实例检入到数据库中的频率(单位:毫秒)。
#Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。
#通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)。
org.quartz.jobStore.clusterCheckinInterval = 20000
创建applicationContext.xml(spring配置文件),说明:由于quartz核心对象Scheduler封装了job和trigger的CRUD操作,所以在spring的配置文件中定义了两个dataSource,分别用于工程中和Schduler中
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 引入配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="${username_}" />
<property name="password" value="${password_}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${maxWait}"></property>
</bean>
<!-- 为了区分工程中的dataSource和quartz用的dataSource(不区分也是可以的) -->
<bean id="qrtz_dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${qrtz_driverClassName}" />
<property name="url" value="${qrtz_url}" />
<property name="username" value="${qrtz_username_}" />
<property name="password" value="${qrtz_password_}" />
</bean>
</beans>
</bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.bh.task.**.mapper"/><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /></bean><bean class="com.bh.task.listener.service.impl.ListenerServiceImpl"/></beans> 创建applicationCnontext-quartz.xml(spring整合quartz配置文件)
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 配置quartz -->
<!-- 配置jobDetail start -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.bh.task.utils.MyJob"/>
<property name="durability" value="true"></property>
</bean>
<!-- 配置jobDetail end -->
<!-- 配置trigger start -->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="cronExpression" value="0/5 * * * * ?"/>
</bean>
<!-- 配置trigger end -->
<!-- 执行实际的调度器 start-->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="qrtz_dataSource"/>
<property name="configLocation" value="classpath:quartz.properties"/>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey"/>
<pre name="code" class="html"> <property name="triggers">
<list>
<ref bean="trigger"/>
</list>
</property>
</bean>
</beans>
web.xml中加载spring文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml,classpath:applicationContext-quartz.xml</param-value>
</context-param>
别忘记listener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
此时集群环境基本完成。