spring&quartz

spring&quartz的项目应用总结
一.名词简介:
       Quartz是一个完全由java编写的开源作业调度框架。Spring为创建Quartz的Scheduler、Trigger和JobDetail提供了便利的FactoryBean类,以便能够在 Spring 容器中享受注入的好处。此外Spring还提供了一些便利工具类直接将Spring中的Bean包装成合法的任务。Spring进一步降低了使用 Quartz的难度,能以更具Spring风格的方式使用Quartz。概括来说它提供了两方面的支持:
    1)为Quartz的重要组件类提供更具Bean风格的扩展类;
    2)提供创建Scheduler的BeanFactory类,方便在Spring环境下创建对应的组件对象,并结合Spring容器生命周期进行启动和停止的动作。

二。项目实践

情景一: 集群部署,持久化,动态创建schedule配置
1.spring-schedule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<bean id="GMTZone" class="java.util.TimeZone" factory-method="getTimeZone">
        <constructor-arg value="GMT"/>
</bean>

<!--业务job生成工厂,该工厂注入了scheduleManager -->
<bean id="pharmaskyJobFactory" class="com.infowarelab.pharmasky.service.schedule.PharmaskyJobFactory"/>

<!--schedule管理器,用于动态添加,修改,删除schedule  -->
<bean id="scheduleManager" class="com.infowarelab.pharmasky.service.schedule.ScheduleManager">
        <property name="scheduler" ref="scheduleFactoryBean"/>
</bean>

<!--持久化,集群schedule工厂配置信息,实际可以在classpath下附加quartz.properties定义这些属性值 -->
<bean id="scheduleFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="quartzProperties">
         <props>
                <prop key="org.quartz.scheduler.instanceName">PharmaskyClusteredScheduler</prop>
                <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
                <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
                <prop key="org.quartz.threadPool.threadCount">25</prop>
                <prop key="org.quartz.threadPool.threadPriority">5</prop>
                <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
                <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
                <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
                <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
                <prop key="org.quartz.jobStore.isClustered">true</prop>
                <prop key="org.quartz.jobStore.clusterCheckinInterval">20000</prop>
         </props>
        </property>
        <property name="triggers">
                 <list>
                         <ref local="orderConversionCronTrigger"/>
                 </list>
         </property>
</bean>

  <!--固定jobDetail, org.quartz.JobDetail类型的JobDetail必须实现指定接口方法来执行job-->
<bean id="autoOrderStatusConversionJob" class="org.quartz.JobDetail">
        <property name="jobClass">
                  <value>com.infowarelab.pharmasky.service.schedule.job.HisAutoOrderConversionJob</value>
        </property>
        <property name="name" value="PMS-SYS-JOB-HIS-ORDER-CONVERSION"/>
        <property name="group" value="PMS-GROUP"/>
        <property name="requestsRecovery" value="true"/>
</bean>

<!--job触发器,绑定上面的jobDetail -->
<bean id="orderConversionCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
         <property name="beanName" value="PMS-SYS-JOB-HIS-ORDER-CONVERSION-Trigger"/>
         <property name="jobDetail" ref="autoOrderStatusConversionJob" />
         <property name="cronExpression" value="0 0/20 * * * ?" />
         <property name="timeZone" ref="GMTZone"/>
  </bean>
</beans>
2.ScheduleManager.java动态管理schedule工具类

ScheduleManager.java
package com.infowarelab.pharmasky.service.schedule;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;

import com.infowarelab.common.log.Log;
import com.infowarelab.common.log.LogFactory;
import com.infowarelab.pharmasky.util.Config;


public class ScheduleManager {

    private static final Log log = LogFactory.getLog(ScheduleManager.class);

    private Scheduler scheduler;

    public void start() throws SchedulerException {
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        if (scheduler.isShutdown() || scheduler.isInStandbyMode()) {
            scheduler.start();
        }
    }

    public void pause() throws SchedulerException {
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        if (scheduler.isStarted()) {
            scheduler.standby();
        }
    }

    public void stop() throws SchedulerException {
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        if (scheduler.isStarted() || scheduler.isInStandbyMode()) {
            scheduler.shutdown();
        }
    }

    public List listJobDetails() throws SchedulerException {
        List rstList = new ArrayList<JobDetail>();
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        String[] groupNames = scheduler.getJobGroupNames();
        log.info("[INFO] the groups in current scheduler is : "
                + groupNames.length);
        for (int i = 0; i < groupNames.length; i++) {
            String[] jobNames = scheduler.getJobNames(groupNames[i]);
            for (int j = 0; j < jobNames.length; j++) {
                JobDetail jobDetail = scheduler.getJobDetail(jobNames[j],
                        groupNames[i]);
                if (jobDetail != null) {
                    rstList.add(jobDetail);
                }
            }
        }
        return rstList;
    }

    public JobDetail getJobDetail(String jobName, String jobGroupName)
            throws SchedulerException {
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        JobDetail job = scheduler.getJobDetail(jobName, jobGroupName);

        if (job == null) {
            log.info("[INFO]none object relative the jobName : " + jobName
                    + " and jobGroupName : " + jobGroupName);
        }
        return job;
    }

    public List<JobDetail> getJobDetailByGroup(String jobGroupName)
            throws SchedulerException {
        List<JobDetail> list = new ArrayList<JobDetail>();
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        String[] jobNames = scheduler.getJobNames(jobGroupName);

        log.debug("[DEBUG] jobNames with \"" + jobGroupName
                + "\" as groupName : " + jobNames);

        for (int i = 0; i < jobNames.length; i++) {
            JobDetail jobDetail = getJobDetail(jobNames[i], jobGroupName);
            if (jobDetail != null) {
                list.add(jobDetail);
            } else {
                log
                        .debug("[DEBUG] JobDetail with {\""
                                + jobNames[i]
                                + "\" , \""
                                + jobGroupName
                                + "\"} as the jobName and jobGroupName can not be found !");
            }
        }
        return list;
    }

    public boolean addJobDetail(JobDetail jobDetail, String cronExpress)
            throws SchedulerException, ParseException {
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        if (jobDetail != null && cronExpress != null) {

            Trigger trigger = new CronTrigger(jobDetail.getName(), jobDetail.getGroup(),
                    jobDetail.getName(), jobDetail.getGroup(), cronExpress);

            Date jobDate = scheduler.scheduleJob(jobDetail, trigger);
            log
                    .info("[INFO]jobDetail : "
                            + jobDetail.getFullName()
                            + " has been added into the scheduler , and the firstFiredTime is : "
                            + jobDate);
            return (jobDate == null) ? false : true;
        } else {
            log
                    .info("[INFO]add jobDetail failure, the parameters on jobDetail or trigger has null value !");
        }
        return false;
    }

    public Trigger[] getJobTrigger(String jobName, String jobGroupName)
            throws SchedulerException {
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        return scheduler.getTriggersOfJob(jobName, jobGroupName);
    }

    public List<Trigger> listTrigger() throws SchedulerException {
        List<Trigger> triggerList = new ArrayList<Trigger>();
        if (scheduler == null) {
            scheduler = getScheduler();
        }
        String[] triggerGroupNames = scheduler.getTriggerGroupNames();
        log
                .info("[INFO] the trigger groups amounts which is registed within the system is : "
                        + triggerGroupNames.length);
        for (String triggerGroupName : triggerGroupNames) {
            if (triggerGroupName != null) {
                String[] triggerNames = scheduler
                        .getTriggerNames(triggerGroupName);
                for (String triggerName : triggerNames) {
                    Trigger trigger = scheduler.getTrigger(triggerName,
                            triggerGroupName);
                    if (trigger != null
                            && scheduler.getTriggerState(triggerName,
                                    triggerGroupName) == Trigger.STATE_NORMAL) {
                        triggerList.add(trigger);
                    } else {
                        log.info("[INFO] the trigger : "
                                + ((trigger == null) ? trigger.getFullName()
                                        : " null") + ", not exists "
                                + "or has the not normal status");
                    }
                }
            }
        }
        return triggerList;
    }

    public boolean reScheduleJob(String jobName, String jobGroupName,
            String computedStr) throws SchedulerException, ParseException {
        if (scheduler == null) {
            scheduler = getScheduler();
        }

        Trigger newTrigger = new CronTrigger(jobName, jobGroupName, jobName,
                jobGroupName, computedStr);

        newTrigger.setJobName(jobName);
        newTrigger.setJobGroup(jobGroupName);


        Date triggerDate = scheduler.rescheduleJob(jobName, jobGroupName, newTrigger);
        log.info("[INFO] the job " + jobName
                + " has been update to fired on : " + triggerDate);

        return (triggerDate == null) ? false : true;
    }

    public String genScheduleTimeStr(byte type, Short scheduleTimeParams) {
        String pattern = null; // variable for cron express
        switch (type) {
        case 1:
            // auto order creation job , the parameter turn is : weekInterval ,
            // weekday, hour, minute
            // "0 minute hour ? * weekDay/weekInterval"
            pattern = Config
                    .getString("schedule.cron.express.his.order.creation");
            log.info("[INFO] parttern for his order creation cron express : "
                    + pattern);
            for (int i = 0; i < scheduleTimeParams.length; i++) {
                switch (i) {
                case 0: // minute
                    pattern = StringUtils.replace(pattern, "minute",
                            scheduleTimeParams[0].toString());
                    break;
                case 1: // hour
                    pattern = StringUtils.replace(pattern, "hour",
                            scheduleTimeParams[1].toString());
                    break;
                case 2: // weekDay
                    pattern = StringUtils.replace(pattern, "weekDay",
                            getWeekIdentify(scheduleTimeParams[2]));
                    break;
                case 3: // weekInterval
                    pattern = StringUtils.replace(pattern, "weekInterval",
                            scheduleTimeParams[3].toString());
                    break;
                default:
                    break;
                }
            }
            break;

        case 2:
            // his stock sync job , the parameter turn is : dayInterval, hour,
            // minute
            // "0 minute hour */dayInterval * ?"
            pattern = Config.getString("schedule.cron.express.his.stock.sync");
            log.info("[INFO] parttern for his order creation cron express : "
                    + pattern);
            for (int i = 0; i < scheduleTimeParams.length; i++) {
                switch (i) {
                case 0: // minute
                    pattern = StringUtils.replace(pattern, "minute",
                            scheduleTimeParams[0].toString());
                    break;
                case 1: // hour
                    pattern = StringUtils.replace(pattern, "hour",
                            scheduleTimeParams[1].toString());
                    break;
                case 2: // dayInterval
                    pattern = StringUtils.replace(pattern, "dayInterval",
                            scheduleTimeParams[2].toString());
                    break;
                default:
                    break;
                }
            }
            break;

        default:
            break;
        }

        log.info("[INFO] schedule job cron express is : " + pattern);
        return (pattern == null) ? null : pattern.trim();
    }

    /** *//** ********************************************************************** */
    /** *//** helper method or getters and setters * */
    /** *//** ********************************************************************** */

    /** *//**
     * get the week day's identify like "SUN","MON" and so on. In this method
     * the data "1" equals "SUN", so the "7" equals "SAT";
     *
     * @param short
     *            the numeric data for week day
     * @return String the week day identify with correct numeric data
     */
    private String getWeekIdentify(short weekDay) {
        String value = null;
        switch (weekDay) {
        case 1:
            value = "SUN";
            break;
        case 2:
            value = "MON";
            break;
        case 3:
            value = "TUE";
            break;
        case 4:
            value = "WED";
            break;
        case 5:
            value = "THU";
            break;
        case 6:
            value = "FRI";
            break;
        case 7:
            value = "SAT";
            break;
        default:
            break;
        }
        return value;
    }

    public Scheduler getScheduler() {
        return scheduler;
    }

    public void setScheduler(Scheduler scheduler) {
        this.scheduler = scheduler;
    }
}



情景二:单机部署,固定触发规则多个schedule,不用持久化
1.spring-schedule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<!-- Job Bean -->
<bean name="autoOrderAuditService" class="com.infowarelab.sam.service.job.AutoOrderAuditService"></bean>
<bean name="sendAuditedOrderService" class="com.infowarelab.sam.service.job.SendAuditedOrderService"></bean>

<!-- Job由于以上job bean具有相同的触发规则,所以统一集中在这个管理器执行-->
<bean id="timerJobManagerJob"  class="com.infowarelab.sam.service.job.SamJobManager"  autowire="no">
       <property name="tasks">
             <list>
                    <ref bean="autoOrderAuditService"/>
                    <ref bean="sendAuditedOrderService"/>
              </list>
        </property>
         <property name="samBaseInfoService" ref="samBaseInfoService"></property>
</bean>

<bean id="timerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" autowire="no">
        <property name="targetObject" ref="timerJobManagerJob" />
        <property name="targetMethod" value="jobExpires" />
</bean>

<bean id="timerCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" autowire="no">
        <property name="jobDetail" ref="timerJobDetail" />
        <property name="cronExpression">
               <value>0 0/15 * * * ?</value>
        </property>
</bean>

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no">
        <property name="triggers">
              <list>
                <ref bean="timerCronTrigger" />
              </list>
        </property>
</bean>
</beans>



参考资料:
cronExpression表达式:
http://hi.baidu.com/the_space_of_programmer/blog/item/725759f78d383e27720eec80.html  (cronExpression
quartz介绍:
http://hi.baidu.com/alliance_alex/blog/item/5c998d64241173f2f73654b0.html
集群及quartz配置说明:
http://hi.baidu.com/jiangyou001/blog/item/5196d990862d5789a977a4af.html
http://gocom.primeton.com/modules/newbb/forumtopic19180_9963_40.htm

你可能感兴趣的:(spring,bean,quartz,项目管理,配置管理)