使用SPRING的定时任务框架,如果是在分布式的环境下,由于有多台节点,会产生相同的任务,会被多个节点执行,这时需引入分布式的QUARTZ。
触发器:存放时间排程
任务:蔟业务代码
排程器:负责调度,即在指定的时间执行对应的任务
如果是分布式QUARTZ,则各个节点会上报任务,存到数据库中,执行时会从数据库中取出触发器来执行,如果触发器的名称和执行时间相同,则只有一个节点去执行此任务。
如果此节点执行失败,则此任务则会被分派到另一节点执行。
quartz.properties
#
============================================================================
#
Configure JobStore
#
Using Spring datasource in quartzJobsConfig.xml
#
Spring uses LocalDataSourceJobStore extension of JobStoreCMT
#
============================================================================
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 5000
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.txIsolationLevelReadCommitted = true
#
Change this to match your DB vendor
org.quartz.jobStore.
class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
============================================================================
#
Configure Main Scheduler Properties
#
Needed to manage cluster instances
#
============================================================================
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.instanceName=MY_CLUSTERED_JOB_SCHEDULER
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
#
============================================================================
#
Configure ThreadPool
#
============================================================================
org.quartz.threadPool.
class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
web-schedule-applicationcontext.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:context
="http://www.springframework.org/schema/context"
xmlns:mongo
="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation
="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
>
<!--
增加定时器配置
-->
<!--
线程执行器配置,用于任务注册
-->
<
bean
id
="executor"
class
="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
>
<
property
name
="corePoolSize"
value
="10"
/>
<
property
name
="maxPoolSize"
value
="100"
/>
<
property
name
="queueCapacity"
value
="500"
/>
</
bean
>
<!--
设置调度
-->
<
bean
id
="webScheduler"
class
="org.springframework.scheduling.quartz.SchedulerFactoryBean"
>
<
property
name
="configLocation"
value
="classpath:/properties/config/quartz.properties"
/>
<
property
name
="dataSource"
ref
="dataSourceCMS"
/>
<
property
name
="transactionManager"
ref
="txManager"
/>
<!--
This name is persisted as SCHED_NAME in db. for local testing could
change to unique name to avoid collision with dev server
-->
<
property
name
="schedulerName"
value
="quartzScheduler"
/>
<!--
Will update database cron triggers to what is in this jobs file on
each deploy. Replaces all previous trigger and job data that was in the database.
YMMV
-->
<
property
name
="overwriteExistingJobs"
value
="true"
/>
<
property
name
="startupDelay"
value
="5"
/>
<
property
name
="applicationContextSchedulerContextKey"
value
="applicationContext"
/>
<
property
name
="jobFactory"
>
<
bean
class
="com.tcl.project7.boss.common.scheduling.AutowiringSpringBeanJobFactory"
/>
</
property
>
<
property
name
="triggers"
>
<
list
>
<
ref
bean
="springQuertzClusterTaskSchedulerTesterTigger"
/>
</
list
>
</
property
>
<
property
name
="jobDetails"
>
<
list
>
<
ref
bean
="springQuertzClusterTaskSchedulerTesterJobDetail"
/>
</
list
>
</
property
>
<
property
name
="taskExecutor"
ref
="executor"
/>
</
bean
>
<!--
触发器
-->
<
bean
id
="springQuertzClusterTaskSchedulerTesterTigger"
class
="common.scheduling.PersistableCronTriggerFactoryBean"
>
<
property
name
="jobDetail"
ref
="springQuertzClusterTaskSchedulerTesterJobDetail"
/>
<
property
name
="cronExpression"
value
="* * * * * ?"
/>
</
bean
>
<
bean
id
="springQuertzClusterTaskSchedulerTesterJobDetail"
class
="org.springframework.scheduling.quartz.JobDetailBean"
>
<
property
name
="jobClass"
value
="common.scheduling.SpringQuertzClusterTaskSchedulerTester"
/>
<!--
fail-over 重写执行失败的任务,default=false
-->
<
property
name
="requestsRecovery"
value
="false"
/>
</
bean
>
</
beans
>
JOB文件:SpringQuertzClusterTaskSchedulerTester.java
package common.scheduling;
import java.util.Date;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import com.tcl.project7.boss.common.util.UrlUtil;
import com.tcl.project7.boss.common.util.time.TimeUtils;
/**
* <p>Title:SpringQuertzClusterTaskSchedulerTester</p>
* <p>Description:
* 应为要持久化等特性操作,需要继承 QuartzJobBean
* <br>由于要被持久化,所以不能存放xxxxManager类似对象,
* 只能从每次从QuartzJobBean注入的ApplicationContext 中去取出
*
* </p>
*
*
*/
public
class SpringQuertzClusterTaskSchedulerTester
extends QuartzJobBean {
private
static Logger logger = LoggerFactory.getLogger(SpringQuertzClusterTaskSchedulerTester.
class);
@Autowired
private UrlUtil urlUtil;
protected
void executeInternal(JobExecutionContext arg0)
throws JobExecutionException {
logger.info("------" + TimeUtils.formatTime(
new Date()) + "------" + urlUtil.getNginxHost());
System.out.println("------" + TimeUtils.formatTime(
new Date()) + "------" + urlUtil.getNginxHost());
}
}
如果JOB中有需要调用SPRING的BEAN,则需要此文件AutowiringSpringBeanJobFactory.java
package common.scheduling;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
/**
* Autowire Quartz Jobs with Spring context dependencies
*
@see
http://stackoverflow.com/questions/6990767/inject-bean-reference-into-a-quartz-job-in-spring/15211030
#15211030
*/
public
final
class AutowiringSpringBeanJobFactory
extends SpringBeanJobFactory
implements ApplicationContextAware {
private
transient AutowireCapableBeanFactory beanFactory;
public
void setApplicationContext(
final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(
final TriggerFiredBundle bundle)
throws Exception {
final Object job =
super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
由于JOB需要存储到数据库中,会产生PROPERTY的问题,需剔除JOB-DATA,需此文件PersistableCronTriggerFactoryBean.java
package common.scheduling;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailAwareTrigger;
/**
* Needed to set Quartz useProperties=true when using Spring classes,
* because Spring sets an object reference on JobDataMap that is not a String
*
*
@see
http://site.trimplement.com/using-spring-and-quartz-with-jobstore-properties/
*
@see
http://forum.springsource.org/showthread.php?130984-Quartz-error-IOException
*/
public
class PersistableCronTriggerFactoryBean
extends CronTriggerFactoryBean {
@Override
public
void afterPropertiesSet() {
super.afterPropertiesSet();
//
Remove the JobDetail element
getJobDataMap().remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
}
}
建表语句,MYSQL:quartzTables.sql
#
# Quartz seems
to
work best
with the driver mm.mysql
-
2.0.
7
-bin.jar
#
#
In your Quartz properties
file, you
‘
ll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
DROP TABLE IF EXISTS QRTZ_JOB_LISTENERS;
DROP TABLE IF EXISTS QRTZ_TRIGGER_LISTENERS;
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS
(
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_VOLATILE VARCHAR(1) NOT NULL,
IS_STATEFUL VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_JOB_LISTENERS
(
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
JOB_LISTENER VARCHAR(200) NOT NULL,
PRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER),
FOREIGN KEY (JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_TRIGGERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
IS_VOLATILE VARCHAR(1) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CRON_TRIGGERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(200) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_BLOB_TRIGGERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_TRIGGER_LISTENERS
(
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
TRIGGER_LISTENER VARCHAR(200) NOT NULL,
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER),
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CALENDARS
(
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (TRIGGER_GROUP)
);
CREATE TABLE QRTZ_FIRED_TRIGGERS
(
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
IS_VOLATILE VARCHAR(1) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_STATEFUL VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
(
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
(
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (LOCK_NAME)
);
INSERT INTO QRTZ_LOCKS values(
‘TRIGGER_ACCESS
‘
);
INSERT INTO QRTZ_LOCKS values(
‘JOB_ACCESS
‘
);
INSERT INTO QRTZ_LOCKS values(
‘CALENDAR_ACCESS
‘
);
INSERT INTO QRTZ_LOCKS values(
‘STATE_ACCESS
‘
);
INSERT INTO QRTZ_LOCKS values(
‘MISFIRE_ACCESS
‘
);
commit;