paulwong

          分布式調(diào)度QUARTZ+SPRING

          使用SPRING的定時(shí)任務(wù)框架,如果是在分布式的環(huán)境下,由于有多臺(tái)節(jié)點(diǎn),會(huì)產(chǎn)生相同的任務(wù),會(huì)被多個(gè)節(jié)點(diǎn)執(zhí)行,這時(shí)需引入分布式的QUARTZ。
          觸發(fā)器:存放時(shí)間排程
          任務(wù):蔟業(yè)務(wù)代碼
          排程器:負(fù)責(zé)調(diào)度,即在指定的時(shí)間執(zhí)行對(duì)應(yīng)的任務(wù)

          如果是分布式QUARTZ,則各個(gè)節(jié)點(diǎn)會(huì)上報(bào)任務(wù),存到數(shù)據(jù)庫(kù)中,執(zhí)行時(shí)會(huì)從數(shù)據(jù)庫(kù)中取出觸發(fā)器來執(zhí)行,如果觸發(fā)器的名稱和執(zhí)行時(shí)間相同,則只有一個(gè)節(jié)點(diǎn)去執(zhí)行此任務(wù)。
          如果此節(jié)點(diǎn)執(zhí)行失敗,則此任務(wù)則會(huì)被分派到另一節(jié)點(diǎn)執(zhí)行。

          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"
          >


              <!-- 增加定時(shí)器配置 -->
              <!-- 線程執(zhí)行器配置,用于任務(wù)注冊(cè) -->
              <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>

              <!-- 設(shè)置調(diào)度 -->
              <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>


              
              
              
              <!-- 觸發(fā)器 -->
              <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 重寫執(zhí)行失敗的任務(wù),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:
           * 應(yīng)為要持久化等特性操作,需要繼承 QuartzJobBean
           * <br>由于要被持久化,所以不能存放xxxxManager類似對(duì)象,
           * 只能從每次從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中有需要調(diào)用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需要存儲(chǔ)到數(shù)據(jù)庫(kù)中,會(huì)產(chǎn)生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);
              }
          }


          建表語(yǔ)句,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;


          參考:
          http://wenku.baidu.com/view/82e3bcbdfd0a79563c1e7223.html

          Quartz集成springMVC 的方案二(持久化任務(wù)、集群和分布式)
          http://blog.csdn.net/congcong68/article/details/39256307















          posted on 2014-11-14 18:46 paulwong 閱讀(14932) 評(píng)論(0)  編輯  收藏 所屬分類: J2EE分布式

          主站蜘蛛池模板: 全南县| 阜新市| 谢通门县| 财经| 胶州市| 英超| 海盐县| 平罗县| 治多县| 奉化市| 虞城县| 兴安盟| 清徐县| 阜阳市| 定远县| 出国| 和政县| 潮安县| 霍山县| 福清市| 江城| 贵州省| 建平县| 阿合奇县| 永仁县| 壶关县| 云阳县| 西乌珠穆沁旗| 资中县| 河东区| 湘潭县| 北川| 临汾市| 荣成市| 洛扎县| 明星| 拜城县| 房产| 昭苏县| 平安县| 保定市|