項目ITP(六) spring4.0 整合 Quartz 實現動態任務調度


2014-05-18 12:51 by Jeff Lihtml

前言

  系列文章:[傳送門]java

  項目需求:spring

     http://www.cnblogs.com/Alandre/p/3733249.html數據庫

     上一博客寫的是基本調度,後來這隻能用於,像天天定個時間 進行數據庫備份。可是,遠遠不能在上次的需求上實現。因此須要實現spring4.0 整合 Quartz 實現動態任務調度。api

 

正文 

  spring4.0 整合 Quartz 實現任務調度。這真是期末項目的最後一篇,剩下到暑假吧。app

    Quartz 介紹

    Quartz is a full-featured, open source job scheduling service that can be integrated with, or used along side virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; 框架

    Quartz框架是一個全功能、開源的任務調度服務,能夠集成幾乎任何的java應用程序—從小的單片機系統到大型的電子商務系統。Quartz能夠執行上千上萬的任務調度。less

 

   核心概念ide

     Quartz核心的概念:scheduler任務調度、Job任務、Trigger觸發器、JobDetail任務細節post

     相關文檔:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/quick-start

回顧

  上次咱們配置了

複製代碼

<!--Quartz-->
            
    <!-- 集成方式:JobDetailFactoryBean,而且任務類須要繼承QuartzJobBean-->
    <!-- 定義jobDetail -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- durability 表示任務完成以後是否依然保留到數據庫,默認false   -->
        <property name="durability" value="true" />  
        <!--     目標類  /wmuitp/src/test/SpringQuartz.java-->
        <property name="jobClass" value="test.SpringQuartzTest"></property>
        
           <!--  在這個例子中,jobDataAsMap沒有用,此目標類中接受的參數 ,若參數爲service,則能夠在此進行參數配置,相似struts2 -->
           <!--
        <property name="jobDataAsMap">  
            <map>  
                <entry key="service"><value>simple is the beat</value></entry>  
            </map>  
        </property>            -->
    </bean>
    
    <!-- 定義simpleTrigger觸發器 -->
    <!--     
    <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="repeatCount">
            <value>8</value>
        </property>
        <property name="repeatInterval">
            <value>1000</value>
        </property>
        <property name="startDelay">
            <value>4</value>
        </property>
    </bean> 
    -->
    
    <!-- 另外一種觸發器是CornTrigger -->
     <bean id="cornTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
       <property name="jobDetail" ref="jobDetail"/>
       <!-- 每一個10秒觸發 -->
       <property name="cronExpression" value="0/10 * * * * ?"/>
    </bean> 
    
    <!-- 定義核心調度器 -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
      <property name="triggers">
        <ref bean="cornTrigger"/>
      </property>
    </bean>

複製代碼

  #spring實現quartz的方式,先看一下上面配置文件中定義的jobDetail。在Quartz 2.x版本中JobDetail已是一個接口,Spring是經過將其轉換爲MethodInvokingJob或StatefulMethodInvokingJob類型來實現的。

 

  這是文檔中的源碼:

複製代碼

/**
 * This implementation applies the passed-in job data map as bean property
 * values, and delegates to <code>executeInternal</code> afterwards.
 * @see #executeInternal */public final void execute(JobExecutionContext context) throws JobExecutionException {    try {        // Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
        Scheduler scheduler = (Scheduler) ReflectionUtils.invokeMethod(getSchedulerMethod, context);
        Map mergedJobDataMap = (Map) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context);
 
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
        MutablePropertyValues pvs = new MutablePropertyValues();
        pvs.addPropertyValues(scheduler.getContext());
        pvs.addPropertyValues(mergedJobDataMap);
        bw.setPropertyValues(pvs, true);
    }    catch (SchedulerException ex) {        throw new JobExecutionException(ex);
    }
    executeInternal(context);
} 
/**
 * Execute the actual job. The job data map will already have been
 * applied as bean property values by execute. The contract is
 * exactly the same as for the standard Quartz execute method.
 * @see #execute */protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException;

複製代碼

 

  MethodInvokingJobDetailFactoryBean中的源碼:

複製代碼

public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException {
    prepare(); 
    // Use specific name if given, else fall back to bean name.
    String name = (this.name != null ? this.name : this.beanName); 
    // Consider the concurrent flag to choose between stateful and stateless job.
    Class jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class); 
    // Build JobDetail instance.
    if (jobDetailImplClass != null) {        // Using Quartz 2.0 JobDetailImpl class...
        this.jobDetail = (JobDetail) BeanUtils.instantiate(jobDetailImplClass);
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this.jobDetail);
        bw.setPropertyValue("name", name);
        bw.setPropertyValue("group", this.group);
        bw.setPropertyValue("jobClass", jobClass);
        bw.setPropertyValue("durability", true);
        ((JobDataMap) bw.getPropertyValue("jobDataMap")).put("methodInvoker", this);
    }    else {        // Using Quartz 1.x JobDetail class...
        this.jobDetail = new JobDetail(name, this.group, jobClass);        this.jobDetail.setVolatility(true);        this.jobDetail.setDurability(true);        this.jobDetail.getJobDataMap().put("methodInvoker", this);
    } 
    // Register job listener names.
    if (this.jobListenerNames != null) {        for (String jobListenerName : this.jobListenerNames) {            if (jobDetailImplClass != null) {                throw new IllegalStateException("Non-global JobListeners not supported on Quartz 2 - " +
                        "manually register a Matcher against the Quartz ListenerManager instead");
            }            this.jobDetail.addJobListener(jobListenerName);
        }
    }
 
    postProcessJobDetail(this.jobDetail);
}

複製代碼

 

  #既然知道了其因此然,咱們就能夠真正實戰了。

實戰 

  聽我慢慢道來

減小spring的配置文件

  爲了實現一個定時任務,spring的配置代碼太多了。動態配置須要們手動來搞。這裏咱們只須要這要配置便可:

    <!-- quartz配置  動態配置因此咱們將 Factory 做爲一個service同樣的接口 QuartzJobFactory.java-->
    <!-- 調度工廠 -->
    <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    </bean>

 

Job實現類

  在這裏我把它看做工廠類:

複製代碼

  QuartzJobFactoryImpl   execute(JobExecutionContext context) "任務成功運行"= (ScheduleJob)context.getMergedJobDataMap().get("scheduleJob""任務名稱 = [" + scheduleJob.getJobName() + "]"

複製代碼

 

任務對應實體類

複製代碼

package test;public class ScheduleJob
{     /** 任務id **/
    private String jobId; 
    /** 任務名稱 **/
    private String jobName; 
    /** 任務分組 **/
    private String jobGroup; 
    /** 任務狀態 0禁用 1啓用 2刪除**/
    private String jobStatus; 
    /** 任務運行時間表達式 **/
    private String cronExpression; 
    /** 任務描述 **/
    private String desc;    public String getJobId()
    {        return jobId;
    }    public void setJobId(String jobId)
    {        this.jobId = jobId;
    }    public String getJobName()
    {        return jobName;
    }    public void setJobName(String jobName)
    {        this.jobName = jobName;
    }    public String getJobGroup()
    {        return jobGroup;
    }    public void setJobGroup(String jobGroup)
    {        this.jobGroup = jobGroup;
    }    public String getJobStatus()
    {        return jobStatus;
    }    public void setJobStatus(String jobStatus)
    {        this.jobStatus = jobStatus;
    }    public String getCronExpression()
    {        return cronExpression;
    }    public void setCronExpression(String cronExpression)
    {        this.cronExpression = cronExpression;
    }    public String getDesc()
    {        return desc;
    }    public void setDesc(String desc)
    {        this.desc = desc;
    }
    
    
}

複製代碼

 

 

下面咱們就來測試下:

Controller 測試代碼:

複製代碼

  @RequestMapping(value = "/quartz")    public ModelAndView quartz() throws SchedulerException 
    {    
        
        //schedulerFactoryBean 由spring建立注入
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
        System.out.println(ctx);
        Scheduler scheduler = (Scheduler)ctx.getBean("schedulerFactoryBean");
        
        System.out.println(scheduler);        //這裏獲取任務信息數據
        List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();        
        for (int i = 0; i < 3; i++) {
            ScheduleJob job = new ScheduleJob();
            job.setJobId("10001" + i);
            job.setJobName("JobName_" + i);
            job.setJobGroup("dataWork");
            job.setJobStatus("1");
            job.setCronExpression("0/5 * * * * ?");
            job.setDesc("數據導入任務");
            jobList.add(job);
        }        for (ScheduleJob job : jobList) {
         
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());         
            //獲取trigger,即在spring配置文件中定義的 bean id="myTrigger"
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);            //不存在,建立一個
            if (null == trigger) {
                JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactoryImpl.class)
                    .withIdentity(job.getJobName(), job.getJobGroup()).build();
                jobDetail.getJobDataMap().put("scheduleJob", job);         
                //表達式調度構建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job
                    .getCronExpression());         
                //按新的cronExpression表達式構建一個新的trigger
                trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).withSchedule(scheduleBuilder).build();
                scheduler.scheduleJob(jobDetail, trigger);
            } else {                // Trigger已存在,那麼更新相應的定時設置                //表達式調度構建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job
                    .getCronExpression());         
                //按新的cronExpression表達式從新構建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder).build();         
                //按新的trigger從新設置job執行                scheduler.rescheduleJob(triggerKey, trigger);
            }
        }
        
        ModelAndView mav = new ModelAndView(AdminWebConstant.ADMIN_LOGIN_VIEW);        return mav;
    }

複製代碼

 

 #後面這塊應該會進一步整理。到時候 會出個更詳細的。期待吧

 

測試結果:

總結

  spring quartz

  

感謝及資源共享

    

    http://url.cn/RzETYu 加入個人羣

    

    路上走來一步一個腳印,但願你們和我一塊兒。

    感謝讀者!很喜歡大家給個人支持。若是支持,點個贊。

    知識來源: 《spring in action》 quartz api

相關文章
相關標籤/搜索