您的位置:首页 > 编程语言 > Java开发

quartz-scheduler集群分布式(并发)部署解决方案-Spring

2016-10-14 14:58 666 查看
<?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:task="http://www.springframework.org/schema/task"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.2.xsd
            http://www.springframework.org/schema/task
            http://www.springframework.org/schema/task/spring-task-3.2.xsd">
  <context:annotation-config />

  <context:component-scan base-package="com.dennis.walking.api.web.schedule" />

  <bean id="rollbackOrderStatus" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

    <property name="jobClass" value="com.dennis.walking.api.web.schedule.ReleaseQtyAndUpdateOrderStatusSchedule" />

    <property name="durability" value="true" />

  </bean>

  <bean id="rollbackOrderStatusTrigger" class="com.dennis.walking.api.web.schedule.PersistableCronTriggerFactoryBean">

    <property name="jobDetail" ref="rollbackOrderStatus" />

    <property name="cronExpression">

      <value>0 0/5 * * * ?</value>

    </property>

    <property name="timeZone">

      <value>GMT+8:00</value>

    </property>

  </bean>

  

 

  <bean id="quartzScheduler" parent="baseQuartzScheduler">

    <property name="configLocation" value="classpath:quartz.properties" />

    <property name="autoStartup" value="true" />

    <!-- 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="apiQuartzScheduler" />

    <!-- NOTE: Must add both the jobDetail and trigger to the scheduler! -->

    <property name="triggers">

      <list>

        <ref bean="rollbackOrderStatusTrigger" /> 

      </list>

    </property>

    <property name="jobDetails">

      <list>

        <ref bean="rollbackOrderStatus" />

      </list>

    </property>

  </bean>

  <bean id="baseQuartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

    <!-- 

    <property name="configLocation" value="classpath:quartz.properties" />

     -->

    <property name="dataSource" ref="dataSource" />

    <property name="transactionManager" ref="transManager" />

    <!-- 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="autoStartup" value="true" />

     -->

    <property name="applicationContextSchedulerContextKey" value="applicationContext" />

    <property name="jobFactory">

      <bean class="com.dennis.walking.api.web.schedule.AutowiringSpringBeanJobFactory" />

    </property>

    <!-- NOTE: Must add both the jobDetail and trigger to the scheduler! -->

    <!-- 

    <property name="jobDetails">

      <list>

      </list>

    </property>

    <property name="triggers">

      <list>

      </list>

    </property>

    -->

  </bean>

</beans>

记得对应下面的三个类文件。

###quartz.properties###

# 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

# 10 mins

org.quartz.jobStore.clusterCheckinInterval=600000

org.quartz.scheduler.skipUpdateCheck=true

# Change this to match your DB vendor

org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate

# Needed to manage cluster instances

org.quartz.scheduler.instanceId=AUTO

org.quartz.scheduler.instanceName=MY_JOB_SCHEDULER

 

org.quartz.scheduler.rmi.export=false

org.quartz.scheduler.rmi.proxy=false

org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool

org.quartz.threadPool.threadCount=10

org.quartz.threadPool.threadPriority=5

org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true

# Configure Plugins

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\}.

quartz定时调度常用时间点设置

"0 0 12 * * ?"                     Fire at 12pm (noon) every day

"0 15 10 ? * *"                   Fire at 10:15am every day

"0 15 10 * * ?"                   Fire at 10:15am every day

"0 15 10 * * ? *"                 Fire at 10:15am every day

"0 15 10 * * ? 2005"           Fire at 10:15am every day during the year 2005

"0 * 14 * * ?"                     Fire every minute starting at 2pm and ending at 2:59pm, every day

"0 0/5 14 * * ?"                  Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day

"0 0/5 14,18 * * ?"              Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day

"0 0-5 14 * * ?"                   Fire every minute starting at 2pm and ending at 2:05pm, every day

"0 10,44 14 ? 3 WED"         Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.

"0 15 10 ? * MON-FRI"        Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday

"0 15 10 15 * ?"                  Fire at 10:15am on the 15th day of every month

"0 15 10 L * ?"                    Fire at 10:15am on the last day of every month

"0 15 10 ? * 6L"                   Fire at 10:15am on the last Friday of every month

"0 15 10 ? * 6L"                   Fire at 10:15am on the last Friday of every month

"0 15 10 ? * 6L 2002-2005"   Fire at 10:15am on every last Friday of every month during the years 2002, 2003, 2004 and 2005

"0 15 10 ? * 6#3"                 Fire at 10:15am on the third Friday of every month

真实运行的业务类:ReleaseQtyAndUpdateOrderStatusSchedule.Java

应为要持久化等特性操作,需要继承 QuartzJobBean

由于要被持久化,所以不能存放xxxxManager类似对象,

只能从每次从QuartzJobBean注入的ApplicationContext 中去取出

继承QuartzJobBean,实现方法executeInternal

package com.dennis.walking.api.web.schedule;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.scheduling.quartz.QuartzJobBean;

import org.springframework.stereotype.Component;

import com.dennis.walking.api.service.OrderService;

@Component

public class ReleaseQtyAndUpdateOrderStatusSchedule extends QuartzJobBean {

  

  private Log log = LogFactory.getLog(this.getClass());

  

  @Autowired

  OrderService orderService;

  

      

  protected void executeInternal(JobExecutionContext arg0)

      throws JobExecutionException {

    log.info("dennis test execute schedule start ");

    try {

      orderService.releaseQtyAndUpdateOrderStatus();

    } catch (Exception e) {

      e.printStackTrace();

      log.error("execute ReleaseQtyAndUpdateOrderStatus schedule error:"

          + e.getMessage());

    }

    log.info("dennis test exxcute schedule end");

  }

}

持久化数据:PersistableCronTriggerFactoryBean.java  保存数据到数据库中

package com.dennis.walking.api.web.schedule;

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();

    System.out.println("PersistableCronTriggerFactoryBean-------------------");

    // Remove the JobDetail element

    getJobDataMap().remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);

  }

}

###AutowiringSpringBeanJobFactory.java### 使用spring的 bean文件时,需要使用此类

package com.dennis.walking.api.web.schedule;

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);

    System.out.println("AutowiringSpringBeanJobFactory-------------------");

    return job;

  }

}

###tables_mysql.sql###  需要建立的11张表

#

# Quartz seems to work best with the driver mysql-connector-java-5.1.34-bin.jar



# PLEASE consider using mysql with innodb tables to avoid locking issues

#

# In your Quartz properties file, you'll need to set 

# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

#

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

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    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_NONCONCURRENT VARCHAR(1) NOT NULL,

    IS_UPDATE_DATA VARCHAR(1) NOT NULL,

    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,

    JOB_DATA BLOB NULL,

    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)

);

CREATE TABLE QRTZ_TRIGGERS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    TRIGGER_NAME VARCHAR(200) NOT NULL,

    TRIGGER_GROUP VARCHAR(200) NOT NULL,

    JOB_NAME  VARCHAR(200) NOT NULL,

    JOB_GROUP VARCHAR(200) 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 (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)

        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)

);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    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 (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

);

CREATE TABLE QRTZ_CRON_TRIGGERS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    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 (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS

  (          

    SCHED_NAME VARCHAR(120) NOT NULL,

    TRIGGER_NAME VARCHAR(200) NOT NULL,

    TRIGGER_GROUP VARCHAR(200) NOT NULL,

    STR_PROP_1 VARCHAR(512) NULL,

    STR_PROP_2 VARCHAR(512) NULL,

    STR_PROP_3 VARCHAR(512) NULL,

    INT_PROP_1 INT NULL,

    INT_PROP_2 INT NULL,

    LONG_PROP_1 BIGINT NULL,

    LONG_PROP_2 BIGINT NULL,

    DEC_PROP_1 NUMERIC(13,4) NULL,

    DEC_PROP_2 NUMERIC(13,4) NULL,

    BOOL_PROP_1 VARCHAR(1) NULL,

    BOOL_PROP_2 VARCHAR(1) NULL,

    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 

    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

);

CREATE TABLE QRTZ_BLOB_TRIGGERS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    TRIGGER_NAME VARCHAR(200) NOT NULL,

    TRIGGER_GROUP VARCHAR(200) NOT NULL,

    BLOB_DATA BLOB NULL,

    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),

    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)

);

CREATE TABLE QRTZ_CALENDARS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    CALENDAR_NAME  VARCHAR(200) NOT NULL,

    CALENDAR BLOB NOT NULL,

    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)

);

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    TRIGGER_GROUP  VARCHAR(200) NOT NULL, 

    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)

);

CREATE TABLE QRTZ_FIRED_TRIGGERS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    ENTRY_ID VARCHAR(95) NOT NULL,

    TRIGGER_NAME VARCHAR(200) NOT NULL,

    TRIGGER_GROUP VARCHAR(200) NOT NULL,

    INSTANCE_NAME VARCHAR(200) NOT NULL,

    FIRED_TIME BIGINT(13) NOT NULL,

    SCHED_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_NONCONCURRENT VARCHAR(1) NULL,

    REQUESTS_RECOVERY VARCHAR(1) NULL,

    PRIMARY KEY (SCHED_NAME,ENTRY_ID)

);

CREATE TABLE QRTZ_SCHEDULER_STATE

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    INSTANCE_NAME VARCHAR(200) NOT NULL,

    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,

    CHECKIN_INTERVAL BIGINT(13) NOT NULL,

    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)

);

CREATE TABLE QRTZ_LOCKS

  (

    SCHED_NAME VARCHAR(120) NOT NULL,

    LOCK_NAME  VARCHAR(40) NOT NULL, 

    PRIMARY KEY (SCHED_NAME,LOCK_NAME)

);

commit;

###如果定时任务比较多,建议增加索引提升速度。

/*

reate index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);  

create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);  

create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);  

create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);  

create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);  

create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);  

create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);  

create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);  

create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);  

create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);  

create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);  

create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);  

create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);  

create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);  

create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);  

create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);  

create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);  

create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);  

create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);  

create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);  

*/

本文测试软件环境使用的jar版本是:

quartz-2.2.1.jar MySQL-connector-java-5.1.34.jar

Linux apache-tomcat-7.0.47 ava version "1.7.0_72" 64位

windows7  Java version "1.7.0_45"  64位 jetty

Quartz是一个开放源码项目,专注于任务调度器,提供了极为广泛的特性如持久化任务,集群和分布式任务等。 Quartz核心是调度器,还采用多线程管理。

1.持久化任务:当应用程序停止运行时,所有调度信息不被丢失,当你重新启动时,调度信息还存在,这就是持久化任务(保存到数据库表中)。

2.集群和分布式处理:当在集群环境下,当有配置Quartz的多个客户端时(节点),采用Quartz的集群和分布式处理时,我们要了解几点好处

1) 一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。

2) Quartz调度是通过触发器的类别来识别不同的任务,在不同的节点定义相同的触发器的类别,这样在集群下能稳定的运行,一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。

3)分布式体现在当相同的任务定时在一个时间点,在那个时间点,不会被两个节点同时执行。

Quartz的 Task(11 张表)实例化采用数据库存储,基于数据库引擎及 High-Available 的策略(集群的一种策略)自动协调每个节点的 Quartz。

参考文章:
http://www.blogjava.net/paulwong/archive/2014/11/14/420104.html http://blog.csdn.net/congcong68/article/details/39252897 http://blog.csdn.net/congcong68/article/details/39256307
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐