• 项目ITP(六) spring4.0 整合 Quartz 实现动态任务调度



    2014-05-18 12:51 by Jeff Li

    前言

      系列文章:[传送门]

      项目需求:

         http://www.cnblogs.com/Alandre/p/3733249.html

         上一博客写的是基本调度,后来这仅仅能用于。像每天定个时间 进行数据库备份。可是,远远不能在上次的需求上实现。所以须要实现spring4.0 整合 Quartz 实现动态任务调度。

     

    正文 

      spring4.0 整合 Quartz 实现任务调度

    这真是期末项目的最后一篇。剩下到暑假吧。

        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能够运行上千上万的任务调度。
     
       核心概念
         Quartz核心的概念:scheduler任务调度、Job任务、Trigger触发器、JobDetail任务细节

    回想

      上次我们配置了

    复制代码
    <!--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实现类

      在这里我把它看作工厂类:

    复制代码
    package test;
    
    import org.quartz.DisallowConcurrentExecution;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    
    @DisallowConcurrentExecution
    public class QuartzJobFactoryImpl implements Job 
    {
    
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException
        {
            System.out.println("任务成功执行");
            ScheduleJob scheduleJob = (ScheduleJob)context.getMergedJobDataMap().get("scheduleJob");
            System.out.println("任务名称 = [" + 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

  • 相关阅读:
    经验总结
    C#小技巧收集总结
    随笔
    看盘做短线的10种方法(转)
    dvbbs 7.1版块图标感应渐变效果 From www.jfeng.cn
    动网的个人文集、个人精华
    dvbbs 文件Dv_News.asp 的外部调用
    动网论坛多系统整合Api接口程序 PDO通行接口开发人员参考规范1.0
    动网首页登陆入口调用
    ASP 有关整合动网论坛的问题
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5328551.html
Copyright © 2020-2023  润新知