spring+quartz+mysql集群

Quartz 中集群如何工作

一個 Quartz 集群中的每個節(jié)點(diǎn)是一個獨(dú)立的 Quartz 應(yīng)用,它又管理著其他的節(jié)點(diǎn)。
意思是你必須對每個節(jié)點(diǎn)分別啟動或停止。不像許多應(yīng)用服務(wù)器的集群,獨(dú)立的 Quartz 節(jié)點(diǎn)并不與另一其的節(jié)點(diǎn)或是管理節(jié)點(diǎn)通信咒劲。
Quartz 應(yīng)用是通過數(shù)據(jù)庫表來感知到另一應(yīng)用的。每個節(jié)點(diǎn)直接與數(shù)據(jù)庫通信诫隅,若離開數(shù)據(jù)庫將對其他節(jié)點(diǎn)一無所知腐魂。

創(chuàng)建Quartz數(shù)據(jù)庫表

因?yàn)镼uartz 集群依賴于數(shù)據(jù)庫,所以必須首先創(chuàng)建Quartz數(shù)據(jù)庫表逐纬。
Quartz 包括了所有被支持的數(shù)據(jù)庫平臺的 SQL 腳本蛔屹。在 quartz目錄/docs/dbTables 目錄下找到那些 SQL 腳本。
這里使用tables_mysql_innodb.sql豁生。

配置文件
  1. 配置jdbc.properties文件
#MySQL配置database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306
database.databaseName=quartz
database.param=useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true
database.username=root
database.password=0123456789
#c3p0配置
c3p0.initialPoolSize=10
c3p0.minPoolSize=10
c3p0.maxPoolSize=10
c3p0.acquireIncrement=5
c3p0.maxIdleTime=0
c3p0.idleConnectionTestPeriod=1800
c3p0.preferredTestQuery=select 1 from dual
c3p0.testConnectionOnCheckout=false
c3p0.testConnectionOnCheckin=true
c3p0.maxStatementsPerConnection=0
c3p0.numHelperThreads=32
  1. 配置spring的spring-dataSource.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:config/jdbc.properties</value>
            </list>
        </property>
    </bean>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${database.driver}" />
       <property name="jdbcUrl" value="${database.url}/${database.databaseName}?${database.param}" />
       <property name="user" value="${database.username}" />
       <property name="password" value="${database.password}" />
        <property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
        <property name="minPoolSize" value="${c3p0.minPoolSize}" />
       <property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
        <property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
        <property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
        <property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}" />
        <property name="preferredTestQuery" value="${c3p0.preferredTestQuery}" />
        <property name="testConnectionOnCheckout" value="${c3p0.testConnectionOnCheckout}" />
        <property name="testConnectionOnCheckin" value="${c3p0.testConnectionOnCheckin}" />
        <property name="maxStatementsPerConnection" value="${c3p0.maxStatementsPerConnection}" />
        <property name="numHelperThreads" value="${c3p0.numHelperThreads}" />
    </bean>
</beans>
  1. 配置quartz.properties文件
#============================================================================   
# Configure Main Scheduler Properties     
#============================================================================
org.quartz.scheduler.instanceName = DefaultQuartzScheduler   
#可為任何值兔毒,用在 JDBC JobStore 中來唯一標(biāo)識實(shí)例,但是所有集群節(jié)點(diǎn)中必須相同甸箱。
org.quartz.scheduler.instanceId = AUTO  
#AUTO即可育叁,基于主機(jī)名和時間戳來產(chǎn)生實(shí)例 ID
#============================================================================   
# 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 
#============================================================================   
# Configure JobStore     
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000 
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX 
#屬性為 JobStoreTX,將任務(wù)持久化到數(shù)據(jù)中芍殖。    
#因?yàn)榧褐泄?jié)點(diǎn)依賴于數(shù)據(jù)庫來傳播 Scheduler 實(shí)例的狀態(tài)豪嗽,你只能在使用 JDBC JobStore 時應(yīng)用Quartz 集群。    
#這意味著你必須使用 JobStoreTX 或是 JobStoreCMT 作為 Job 存儲;你不能在集群中使用 RAMJobStore昵骤。  
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 實(shí)例要它參與到一個集群當(dāng)中。這一屬性會貫穿于調(diào)度框架的始終肯适,用于修改集群環(huán)境中操作的默認(rèn)行為变秦。 
org.quartz.jobStore.clusterCheckinInterval = 20000 
#屬性定義了Scheduler 實(shí)例檢入到數(shù)據(jù)庫中的頻率(單位:毫秒)。默認(rèn)值是 15000 (即15 秒)框舔。
  1. 配置quartz的spring-quartz.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <bean id="simpleService" class="com.hao.service.SimpleService" />  
    <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="applicationContextSchedulerContextKey" value="applicationContextKey"/>
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:config/quartz.properties"/>
        <property name="triggers"> 
        <list>   
            <ref bean="trigger1"/> 
            <ref bean="trigger2"/>
        </list> 
     </property>
    </bean> 
    <bean id="jobDetail1" class="com.hao.MethodInvokingJobDetailFactoryBean"> 
    <property name="concurrent" value="true" /> 
        <property name="targetObject" ref="simpleService"/> 
        <property name="targetMethod" value="testMethod1"/> 
    <property name="shouldRecover" value="true"/> 
    </bean> 
    <bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
        <property name="jobDetail" ref="jobDetail1"/>
        <!-- 每分鐘執(zhí)行1次 -->
        <property name="cronExpression" value="0 0/1 * * * ?"/> 
    </bean>    
    <bean id="jobDetail2" class="com.hao.MethodInvokingJobDetailFactoryBean"> 
    <property name="concurrent" value="true" /> 
        <property name="targetObject" ref="simpleService"/> 
        <property name="targetMethod" value="testMethod2"/>
    <property name="shouldRecover" value="true"/> 
    </bean> 
    <bean id="trigger2" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
        <property name="jobDetail" ref="jobDetail2"/> 
        <property name="cronExpression" value="0 0/1 * * * ?"/> 
    </bean>   
</beans>
創(chuàng)建Job測試服務(wù)類
package com.hao.service;
import java.io.Serializable;
public class SimpleService implements Serializable {
    private static final long serialVersionUID = 1L;
    public void testMethod1() {
        //這里執(zhí)行定時調(diào)度業(yè)務(wù)  
        System.out.println("testMethod1.......1");
    }
    public void testMethod2() {
        System.err.println("testMethod2.......2");
    }
}

因?yàn)镴ob需要持久化到數(shù)據(jù)庫中蹦玫,SimpleService必須實(shí)現(xiàn)Serializable接口。

運(yùn)行Quartz集群
package com.hao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
    public static void main(String[] args) {
        new ClassPathXmlApplicationContext(new String[]{"classpath:config/spring/spring-dataSource.xml","classpath:config/spring/spring-quartz.xml"});  
    }
}

MethodInvokingJobDetailFactoryBean.java

package com.hao;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.StatefulJob;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.MethodInvoker;
/**
 * This is a cluster safe Quartz/Spring FactoryBean implementation, which produces a JobDetail implementation that can invoke any no-arg method on any Class.
 * <p>
 * Use this Class instead of the MethodInvokingJobDetailBeanFactory Class provided by Spring when deploying to a web environment like Tomcat.
 * <p>
 * <b>Implementation</b><br>
 * Instead of associating a MethodInvoker with a JobDetail or a Trigger object, like Spring''s MethodInvokingJobDetailFactoryBean does, I made the [Stateful]MethodInvokingJob, which is not persisted in the database, create the MethodInvoker when the [Stateful]MethodInvokingJob is created and executed.
 * <p>
 * A method can be invoked one of several ways:
 * <ul>
 * <li>The name of the Class to invoke (targetClass) and the static method to invoke (targetMethod) can be specified.
 * <li>The Object to invoke (targetObject) and the static or instance method to invoke (targetMethod) can be specified (the targetObject must be Serializable when concurrent=="false").
 * <li>The Class and static Method to invoke can be specified in one property (staticMethod). example: staticMethod = "example.ExampleClass.someStaticMethod"
 * <br><b>Note:</b>  An Object[] of method arguments can be specified (arguments), but the Objects must be Serializable if concurrent=="false".
 * </ul>  
 * <p>
 * I wrote MethodInvokingJobDetailFactoryBean, because Spring''s MethodInvokingJobDetailFactoryBean does not produce Serializable
 * JobDetail objects, and as a result cannot be deployed into a clustered environment like Tomcat (as is documented within the Class).
 * <p>
 * <b>Example</b>
 * <code>
 * <ul>
 *  &lt;bean id="<i>exampleTrigger</i>" class="org.springframework.scheduling.quartz.CronTriggerBean"&gt;
 * <ul>
    <i>&lt;!-- Execute example.ExampleImpl.fooBar() at 2am every day --&gt;</i><br>
    &lt;property name="<a  value="0 0 2 * * ?" /&gt;<br>
    &lt;property name="jobDetail"&gt;
    <ul>
    &lt;bean class="frameworkx.springframework.scheduling.quartz.<b>MethodInvokingJobDetailFactoryBean</b>"&gt;
    <ul>
    &lt;property name="concurrent" value="<i>false</i>"/&gt;<br>
    &lt;property name="targetClass" value="<i>example.ExampleImpl</i>" /&gt;<br>
    &lt;property name="targetMethod" value="<i>fooBar</i>" /&gt;
    </ul>
    &lt;/bean&gt;
    </ul>
    &lt;/property&gt;
    </ul>
    &lt;/bean&gt;
    <p>
    &lt;bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"&gt;
    <ul>
    &lt;property name="triggers"&gt;
    <ul>
    &lt;list&gt;
    <ul>
    &lt;ref bean="<i>exampleTrigger</i>" /&gt;
    </ul>
    &lt;/list&gt;
    </ul>
    &lt;/property&gt;
    </ul>
    &lt;/bean&gt;
    </ul>
 * </code>
 * In this example we created a MethodInvokingJobDetailFactoryBean, which will produce a JobDetail Object with the jobClass property set to StatefulMethodInvokingJob.class (concurrent=="false"; Set to MethodInvokingJob.class when concurrent=="true"), which will in turn invoke the static <code>fooBar</code>() method of the "<code>example.ExampleImpl</code>" Class. The Scheduler is the heart of the whole operation; without it, nothing will happen.
 * <p>
 * For more information on <code>cronExpression</code> syntax visit <a >http://www.opensymphony.com/quartz/api/org/quartz/CronTrigger.html</a>
 *
 * @author Stephen M. Wick
 *
 * @see #afterPropertiesSet()
 */
public class MethodInvokingJobDetailFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {
    private Log logger = LogFactory.getLog(getClass());
    /**
     * The JobDetail produced by the <code>afterPropertiesSet</code> method of this Class will be assigned to the Group specified by this property.  Default: Scheduler.DEFAULT_GROUP 
     * @see #afterPropertiesSet()
     * @see Scheduler#DEFAULT_GROUP
     */
    private String group = Scheduler.DEFAULT_GROUP;
    /**
     * Indicates whether or not the Bean Method should be invoked by more than one Scheduler at the specified time (like when deployed to a cluster, and/or when there are multiple Spring ApplicationContexts in a single JVM<i> - Tomcat 5.5 creates 2 or more instances of the DispatcherServlet (a pool), which in turn creates a separate Spring ApplicationContext for each instance of the servlet</i>) 
     * <p>
     * Used by <code>afterPropertiesSet</code> to set the JobDetail.jobClass to MethodInvokingJob.class or StatefulMethodInvokingJob.class when true or false, respectively.  Default: true 
     * @see #afterPropertiesSet()
     */
    private boolean concurrent = true;
    /** Used to set the JobDetail.durable property.  Default: false
     * <p>Durability - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it.
     * @see <a >http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html</a> 
     * @see #afterPropertiesSet() 
     */
    private boolean durable = false;
    /**
     * Used by <code>afterPropertiesSet</code> to set the JobDetail.volatile property.  Default: false
     * <p>Volatility - if a job is volatile, it is not persisted between re-starts of the Quartz scheduler.
     * <p>I set the default to false to be the same as the default for a Quartz Trigger.  An exception is thrown 
     * when the Trigger is non-volatile and the Job is volatile.  If you want volatility, then you must set this property, and the Trigger''s volatility property, to true.
     * @see <a >http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html</a>
     * @see #afterPropertiesSet() 
     */
    private boolean volatility = false;
    /** 
     * Used by <code>afterPropertiesSet</code> to set the JobDetail.requestsRecovery property.  Default: false<BR>
     * <p>RequestsRecovery - if a job "requests recovery", and it is executing during the time of a ''hard shutdown'' of the scheduler (i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. In this case, the JobExecutionContext.isRecovering() method will return true. 
     * @see <a >http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html</a>
     * @see #afterPropertiesSet() 
     */
    private boolean shouldRecover = false;
    /**
     * A list of names of JobListeners to associate with the JobDetail object created by this FactoryBean.
     *
     * @see #afterPropertiesSet() 
     **/
    private String[] jobListenerNames;
    /** The name assigned to this bean in the Spring ApplicationContext.
     * Used by <code>afterPropertiesSet</code> to set the JobDetail.name property.
     * @see afterPropertiesSet()
     * @see JobDetail#setName(String)
     **/
    private String beanName;
    /**
     * The JobDetail produced by the <code>afterPropertiesSet</code> method, and returned by the <code>getObject</code> method of the Spring FactoryBean interface.
     * @see #afterPropertiesSet()
     * @see #getObject()
     * @see FactoryBean
     **/
    private JobDetail jobDetail;
    /**
     * The name of the Class to invoke.
     **/
    private String targetClass;
    /**
     * The Object to invoke.
     * <p>
     * {@link #targetClass} or targetObject must be set, but not both.
     * <p>
     * This object must be Serializable when {@link #concurrent} is set to false.
     */
    private Object targetObject;
    /**
     * The instance method to invoke on the Class or Object identified by the targetClass or targetObject property, respectfully.
     * <p>
     * targetMethod or {@link #staticMethod} should be set, but not both. 
     **/
    private String targetMethod;
    /**
     * The static method to invoke on the Class or Object identified by the targetClass or targetObject property, respectfully.
     * <p>
     * {@link #targetMethod} or staticMethod should be set, but not both. 
     */
    private String staticMethod;
    /**
     * Method arguments provided to the {@link #targetMethod} or {@link #staticMethod} specified.
     * <p>
     * All arguments must be Serializable when {@link #concurrent} is set to false.
     * <p>
     * I strongly urge you not to provide arguments until Quartz 1.6.1 has been released if you are using a JDBCJobStore with
     * Microsoft SQL Server. There is a bug in version 1.6.0 that prevents Quartz from Serializing the Objects in the JobDataMap
     * to the database.  The workaround is to set the property "org.opensymphony.quaryz.useProperties = true" in your quartz.properties file,
     * which tells Quartz not to serialize Objects in the JobDataMap, but to instead expect all String compliant values.
     */
    private Object[] arguments;
    /**
     * Get the targetClass property.
     * @see #targetClass
     * @return targetClass
     */
    public String getTargetClass() {
        return targetClass;
    }
    /**
     * Set the targetClass property.
     * @see #targetClass
     */
    public void setTargetClass(String targetClass) {
        this.targetClass = targetClass;
    }
    /**
     * Get the targetMethod property.
     * @see #targetMethod
     * @return targetMethod
     */
    public String getTargetMethod() {
        return targetMethod;
    }
    /**
     * Set the targetMethod property.
     * @see #targetMethod
     */
    public void setTargetMethod(String targetMethod) {
        this.targetMethod = targetMethod;
    }
    /**
     * @return jobDetail - The JobDetail that is created by the afterPropertiesSet method of this FactoryBean
     * @see #jobDetail
     * @see #afterPropertiesSet()
     * @see FactoryBean#getObject()
     */
    public Object getObject() throws Exception {
        return jobDetail;
    }
    /**
     * @return JobDetail.class
     * @see FactoryBean#getObjectType()
     */
    public Class getObjectType() {
        return JobDetail.class;
    }
    /**
     * @return true
     * @see FactoryBean#isSingleton()
     */
    public boolean isSingleton() {
        return true;
    }
    /**
     * Set the beanName property.
     * @see #beanName
     * @see BeanNameAware#setBeanName(String)
     */
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
    /**
     * Invoked by the Spring container after all properties have been set.
     * <p>
     * Sets the <code>jobDetail</code> property to a new instance of JobDetail
     * <ul>
     * <li>jobDetail.name is set to <code>beanName</code><br>
     * <li>jobDetail.group is set to <code>group</code><br>
     * <li>jobDetail.jobClass is set to MethodInvokingJob.class or StatefulMethodInvokingJob.class depending on whether the <code>concurrent</code> property is set to true or false, respectively.<br>
     * <li>jobDetail.durability is set to <code>durable</code>
     * <li>jobDetail.volatility is set to <code>volatility</code>
     * <li>jobDetail.requestsRecovery is set to <code>shouldRecover</code>
     * <li>jobDetail.jobDataMap["targetClass"] is set to <code>targetClass</code>
     * <li>jobDetail.jobDataMap["targetMethod"] is set to <code>targetMethod</code>
     * <li>Each JobListener name in <code>jobListenerNames</code> is added to the <code>jobDetail</code> object.
     * </ul>
     * <p>
     * Logging occurs at the DEBUG and INFO levels; 4 lines at the DEBUG level, and 1 line at the INFO level.
     * <ul>
     * <li>DEBUG: start
     * <li>DEBUG: Creating JobDetail <code>{beanName}</code>
     * <li>DEBUG: Registering JobListener names with JobDetail object <code>{beanName}</code>
     * <li>INFO: Created JobDetail: <code>{jobDetail}</code>; targetClass: <code>{targetClass}</code>; targetMethod: <code>{targetMethod}</code>;
     * <li>DEBUG: end
     * </ul>
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     * @see JobDetail
     * @see #jobDetail
     * @see #beanName
     * @see #group
     * @see MethodInvokingJob
     * @see StatefulMethodInvokingJob
     * @see #durable
     * @see #volatility
     * @see #shouldRecover
     * @see #targetClass
     * @see #targetMethod
     * @see #jobListenerNames 
     */
    public void afterPropertiesSet() throws Exception {
        try {
            logger.debug("start");
            logger.debug("Creating JobDetail " + beanName);
            jobDetail = new JobDetail();
            jobDetail.setName(beanName);
            jobDetail.setGroup(group);
            jobDetail.setJobClass(concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
            jobDetail.setDurability(durable);
            jobDetail.setVolatility(volatility);
            jobDetail.setRequestsRecovery(shouldRecover);
            if (targetClass != null)
                jobDetail.getJobDataMap().put("targetClass", targetClass);
            if (targetObject != null)
                jobDetail.getJobDataMap().put("targetObject", targetObject);
            if (targetMethod != null)
                jobDetail.getJobDataMap().put("targetMethod", targetMethod);
            if (staticMethod != null)
                jobDetail.getJobDataMap().put("staticMethod", staticMethod);
            if (arguments != null)
                jobDetail.getJobDataMap().put("arguments", arguments);
            logger.debug("Registering JobListener names with JobDetail object " + beanName);
            if (this.jobListenerNames != null) {
                for (int i = 0; i < this.jobListenerNames.length; i++) {
                    this.jobDetail.addJobListener(this.jobListenerNames[i]);
                }
            }
            logger.info("Created JobDetail: " + jobDetail + "; targetClass: " + targetClass + "; targetObject: " + targetObject + "; targetMethod: "
                    + targetMethod + "; staticMethod: " + staticMethod + "; arguments: " + arguments + ";");
        } finally {
            logger.debug("end");
        }
    }
    /**
     * Setter for the concurrent property.
     * 
     * @param concurrent
     * @see #concurrent
     */
    public void setConcurrent(boolean concurrent) {
        this.concurrent = concurrent;
    }
    /**
     * setter for the durable property.
     * 
     * @param durable
     * 
     * @see #durable
     */
    public void setDurable(boolean durable) {
        this.durable = durable;
    }
    /**
     * setter for the group property.
     * 
     * @param group
     * 
     * @see #group
     */
    public void setGroup(String group) {
        this.group = group;
    }
    /**
     * setter for the {@link #jobListenerNames} property.
     * 
     * @param jobListenerNames
     * @see #jobListenerNames
     */
    public void setJobListenerNames(String[] jobListenerNames) {
        this.jobListenerNames = jobListenerNames;
    }
    /**
     * setter for the {@link #shouldRecover} property.
     *
     * @param shouldRecover
     * @see #shouldRecover
     */
    public void setShouldRecover(boolean shouldRecover) {
        this.shouldRecover = shouldRecover;
    }
    /**
     * setter for the {@link #volatility} property.
     * 
     * @param volatility
     * @see #volatility
     */
    public void setVolatility(boolean volatility) {
        this.volatility = volatility;
    }
    /**
     * This is a cluster safe Job designed to invoke a method on any bean defined within the same Spring
     * ApplicationContext.
     * <p>
     * The only entries this Job expects in the JobDataMap are "targetClass" and "targetMethod".<br>
     * - It uses the value of the <code>targetClass</code> entry to get the desired bean from the Spring ApplicationContext.<br>
     * - It uses the value of the <code>targetMethod</code> entry to determine which method of the Bean (identified by targetClass) to invoke.
     * <p>
     * It uses the static ApplicationContext in the MethodInvokingJobDetailFactoryBean,
     * which is ApplicationContextAware, to get the Bean with which to invoke the method.
     * <p>
     * All Exceptions thrown from the execute method are caught and wrapped in a JobExecutionException.
     * 
     * @see MethodInvokingJobDetailFactoryBean#applicationContext
     * @see #execute(JobExecutionContext)
     * 
     * @author Stephen M. Wick
     */
    public static class MethodInvokingJob implements Job {
        protected Log logger = LogFactory.getLog(getClass());
        /**
         * When invoked by a Quartz scheduler, <code>execute</code> invokes a method on a Class or Object in the JobExecutionContext provided.
         * <p>
         * <b>Implementation</b><br>
         * The Class is identified by the "targetClass" entry in the JobDataMap of the JobExecutionContext provided.  If targetClass is specified, then targetMethod must be a static method.<br>
         * The Object is identified by the ''targetObject" entry in the JobDataMap of the JobExecutionContext provided.  If targetObject is provided, then targetClass will be overwritten.  This Object must be Serializable when <code>concurrent</code> is set to false.<br>
         * The method is identified by the "targetMethod" entry in the JobDataMap of the JobExecutionContext provided.<br>
         * The "staticMethod" entry in the JobDataMap of the JobExecutionContext can be used to specify a Class and Method in one entry (ie: "example.ExampleClass.someStaticMethod")<br>
         * The method arguments (an array of Objects) are identified by the "arguments" entry in the JobDataMap of the JobExecutionContext.  All arguments must be Serializable when <code>concurrent</code> is set to false.
         * <p>
         * Logging is provided at the DEBUG and INFO levels; 8 lines at the DEBUG level, and 1 line at the INFO level.
         * @see Job#execute(JobExecutionContext)
         */
        public void execute(JobExecutionContext context) throws JobExecutionException {
            try {
                logger.debug("start");
                String targetClass = context.getMergedJobDataMap().getString("targetClass");
                logger.debug("targetClass is " + targetClass);
                Class targetClassClass = null;
                if (targetClass != null) {
                    targetClassClass = Class.forName(targetClass); // Could throw ClassNotFoundException
                }
                Object targetObject = context.getMergedJobDataMap().get("targetObject");
                logger.debug("targetObject is " + targetObject);
                String targetMethod = context.getMergedJobDataMap().getString("targetMethod");
                logger.debug("targetMethod is " + targetMethod);
                String staticMethod = context.getMergedJobDataMap().getString("staticMethod");
                logger.debug("staticMethod is " + staticMethod);
                Object[] arguments = (Object[]) context.getMergedJobDataMap().get("arguments");
                logger.debug("arguments are " + arguments);
                logger.debug("creating MethodInvoker");
                MethodInvoker methodInvoker = new MethodInvoker();
                methodInvoker.setTargetClass(targetClassClass);
                methodInvoker.setTargetObject(targetObject);
                methodInvoker.setTargetMethod(targetMethod);
                methodInvoker.setStaticMethod(staticMethod);
                methodInvoker.setArguments(arguments);
                methodInvoker.prepare();
                logger.info("Invoking: " + methodInvoker.getPreparedMethod().toGenericString());
                methodInvoker.invoke();
            } catch (Exception e) {
                throw new JobExecutionException(e);
            } finally {
                logger.debug("end");
            }
        }
    }
    public static class StatefulMethodInvokingJob extends MethodInvokingJob implements StatefulJob {
        // No additional functionality; just needs to implement StatefulJob.
    }
    public Object[] getArguments() {
        return arguments;\n }\n\n   public void setArguments(Object[] arguments) {
        this.arguments = arguments;
    }
    public String getStaticMethod() {
        return staticMethod;
    }
    public void setStaticMethod(String staticMethod) {
        this.staticMethod = staticMethod;
    }
    public void setTargetObject(Object targetObject) {
        this.targetObject = targetObject;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刘绣,一起剝皮案震驚了整個濱河市樱溉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纬凤,老刑警劉巖福贞,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異停士,居然都是意外死亡挖帘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門恋技,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拇舀,“玉大人,你說我怎么就攤上這事蜻底〗颈溃” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵薄辅,是天一觀的道長要拂。 經(jīng)常有香客問我,道長站楚,這世上最難降的妖魔是什么宇弛? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮源请,結(jié)果婚禮上枪芒,老公的妹妹穿的比我還像新娘。我一直安慰自己谁尸,他們只是感情好舅踪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著良蛮,像睡著了一般抽碌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天货徙,我揣著相機(jī)與錄音左权,去河邊找鬼。 笑死痴颊,一個胖子當(dāng)著我的面吹牛赏迟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蠢棱,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼锌杀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泻仙?” 一聲冷哼從身側(cè)響起糕再,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎玉转,沒想到半個月后突想,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡究抓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年蒿柳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漩蟆。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡垒探,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怠李,到底是詐尸還是另有隱情圾叼,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布捺癞,位于F島的核電站夷蚊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏髓介。R本人自食惡果不足惜惕鼓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望唐础。 院中可真熱鬧箱歧,春花似錦、人聲如沸一膨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豹绪。三九已至价淌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝉衣。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工括尸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人病毡。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓濒翻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親剪验。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容