zoukankan      html  css  js  c++  java
  • quartz教程

    本文转自:http://blog.csdn.net/huihuimimi17/article/details/8215779 感谢作者 

    什么是Quartz


    Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。简单地创建一个org.quarz.Job接口的Java类,Job接口包含唯一的方法:
     
        public void execute(JobExecutionContext context) throws JobExecutionException;
     
    在Job接口实现类里面,添加需要的逻辑到execute()方法中。配置好Job实现类并设定好调度时间表,Quartz就会自动在设定的时间调度作业执行execute()。
     
    整合了Quartz的应用程序可以重用不同事件的作业,还可以为一个事件组合多个作业。Quartz通过属性文件来配置JDBC事务的数据源、全局作业、触发器侦听器、插件、线程池等等。
     
    Quartz是由James House创建并最初于2001年春天被加入sourceforge工程。接下来的几年里,有很多的新特性和版本出现,但是直到项目迁移到新的站点并成为OpenSymphony项目家族的一员,才开始真正启动并受到也有的关注。
     
    目前的版本已经是2.0以上,v2.x相对于v1.x有很多新特性出现,并有很多的改动,具体参见Quartz官网上说明。这里介绍的仍然是v1.x(v1.8.6)。
     
     

     "Hello, Quartz"


     
    配置环境:
    1. 下载Quartz
    2. 阅读Readme.txt,了解每个jar包的作用,将quartz.jar包和lib/下的几个jar包、以及相关依赖的jar包放在工程的classpath中
     
    先来看一个简单的Quartz应用,让它每隔5s打印"Hello, Quartz",打印10次。
     
    代码清单1:创建任务
     
    import java.util.Date;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;

    public class HelloQuartzJob implements Job {

        public void execute(JobExecutionContext context) 
                throws JobExecutionException {
            System.out.println("Hello, Quartz! - executing its JOB at "+ 
                new Date() + " by " + context.getTrigger().getName());
        }
    }
     
     
    为了调度此任务执行,需要先得到一个Schedule实例,然后创建一个包含任务信息的JobDetail,最后创建一个Trigger管理任务的执行。
     
    代码清单2:调度任务
    import java.sql.Date; 
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SchedulerFactory;
    import org.quartz.SimpleTrigger;
    import org.quartz.impl.StdSchedulerFactory;


    public class HelloQuartzScheduling {

        public static void main(String[] args)throws SchedulerException {

            SchedulerFactory schedulerFactory = new StdSchedulerFactory();
            Scheduler scheduler = schedulerFactory.getScheduler();

            JobDetail jobDetail = new JobDetail("helloQuartzJob", 
                    Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

            SimpleTrigger simpleTrigger = new SimpleTrigger("simpleTrigger", 
                    Scheduler.DEFAULT_GROUP);

            simpleTrigger.setStartTime(new Date(System.currentTimeMillis()));
            simpleTrigger.setRepeatInterval(5000);
            simpleTrigger.setRepeatCount(10);

            scheduler.scheduleJob(jobDetail, simpleTrigger);

            scheduler.start();
        }

    }
     
    运行结果:
     
    可以看到,其实它执行了11次。此处没有配置log4j.properties属性文件。
     

    CronTrigger类


     
    Quartz有两大触发器,除了上面使用的SimpleTrigger外,就是CronTrigger。CronTrigger能够提供复杂的触发器表达式的支持。CronTrigger是基于Unix Cron守护进程,它是一个调度程序,支持简单而强大的触发器语法。
     
    使用CronTrigger主要的是要掌握Cron表达式。Cron表达式包含6个必要组件和一个可选组件,如下表所示。
     

    位置

    含义

    允许的特殊字符

    1

    秒(0~59)

    , -  *  /

    2

    分(0~59)

    , -  *  /

    3

    小时(0~24)

    , -  *  /

    4

    日期(1~31)

    , -  *  /  ?  L  W  C

    5

    月(JAN~DEC或1~12)

    , -  *  /

    6

    星期(SUN~SAT或1~7)

    , -  *  /  ?  L  C  #

    7

    年(可选,1970~2099),若为空,表示全部时间范围

    , -  *  /

     
    特殊字符的含义,见下表。
     

    特殊字符

    说明

    *

    通配符,任意值

    ?

    无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查

    -

    范围。e.g.小时部分10-12表示10:00,11:00, 12:00

    ,

    列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON、TUE和WED

    /

    增量。表示一个值的增量,e.g.分钟域中0/1表示从0开始,每次增加1min

    L

    表示Last。它在日期和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中,它永远是7(星期六)。当你希望使用星期中某一天时,L字符非常有用。e.g.星期域中6L表示每一个月的最后一个星期五

    W

    在本月内离当天最近的工作日触发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离是0;所谓本月内指的是不能跨月取到最近工作日,即使前/后月份的最后一天/第一天确实满足最近工作日。e.g. LW表示本月的最后一个工作日触发,W强烈依赖月份。

    #

    表示该月的第几个星期,e.g. 1#2表示每一个月的第一个星期一

    C

    日历值。日期值是根据一个给定的日历计算出来的。在日期域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。例如在一个星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五)

     
    Cron表达式举例:
     
    "30 * * * * ?" 每半分钟触发任务
    "30 10 * * * ?" 每小时的10分30秒触发任务
    "30 10 1 * * ?" 每天1点10分30秒触发任务
    "30 10 1 20 * ?" 每月20号1点10分30秒触发任务
    "30 10 1 20 10 ? *" 每年10月20号1点10分30秒触发任务
    "30 10 1 20 10 ? 2011" 2011年10月20号1点10分30秒触发任务
    "30 10 1 ? 10 * 2011" 2011年10月每天1点10分30秒触发任务
    "30 10 1 ? 10 SUN 2011" 2011年10月每周日1点10分30秒触发任务
    "15,30,45 * * * * ?" 每15秒,30秒,45秒时触发任务
    "15-45 * * * * ?" 15到45秒内,每秒都触发任务
    "15/5 * * * * ?" 每分钟的每15秒开始触发,每隔5秒触发一次
    "15-30/5 * * * * ?" 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
    "0 0/3 * * * ?" 每小时的第0分0秒开始,每三分钟触发一次
    "0 15 10 ? * MON-FRI" 星期一到星期五的10点15分0秒触发任务
    "0 15 10 L * ?" 每个月最后一天的10点15分0秒触发任务
    "0 15 10 LW * ?" 每个月最后一个工作日的10点15分0秒触发任务
    "0 15 10 ? * 5L" 每个月最后一个星期四的10点15分0秒触发任务
    "0 15 10 ? * 5#3" 每个月第三周的星期四的10点15分0秒触发任务
     
    将上面HelloQuartz例子中SimpleTrigger换成CronTrigger,代码如下。
     
    代码清单3:CronTrigger调度器
    import java.text.ParseException;
    import org.quartz.CronTrigger;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SchedulerFactory;
    import org.quartz.impl.StdSchedulerFactory;

    public class HelloQuartzScheduling {

        public static void main(String[] args) 
            throws SchedulerException, ParseException {

            SchedulerFactory schedulerFactory = new StdSchedulerFactory();
            Scheduler scheduler = schedulerFactory.getScheduler();

            JobDetail jobDetail = new JobDetail("helloQuartzJob", 
                    Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

            String cronExpression = "30/5 * * * * ?"; // 每分钟的30s起,每5s触发任务        
            CronTrigger cronTrigger = new CronTrigger("cronTrigger", 
                    Scheduler.DEFAULT_GROUP, cronExpression);

            scheduler.scheduleJob(jobDetail, cronTrigger);

            scheduler.start();
        }

    }
     
    运行结果:
     
    CronTrigger使用HolidayCalendar类可以排除某一段时间,比如说国庆节不执行调度任务,代码示例如下:
     
    代码清单4:HolidayCalendar的使用
    import java.text.ParseException;
    import java.util.Calendar;
    import org.quartz.CronTrigger;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SchedulerFactory;
    import org.quartz.impl.StdSchedulerFactory;
    import org.quartz.impl.calendar.HolidayCalendar;


    public class HelloQuartzScheduling {

        public static void main(String[] args) 
            throws SchedulerException, ParseException {

            SchedulerFactory schedulerFactory = new StdSchedulerFactory();
            Scheduler scheduler = schedulerFactory.getScheduler();

            JobDetail jobDetail = new JobDetail("helloQuartzJob", 
                    Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

            Calendar cal = Calendar.getInstance();
            cal.set(2012, Calendar.OCTOBER, 1); // 国庆节

            HolidayCalendar holidayCal = new HolidayCalendar();
            holidayCal.addExcludedDate(cal.getTime()); // 排除该日期

            // addCalendar(String calName, Calendar calendar, 
            //             boolean replace, boolean updateTriggers)
            scheduler.addCalendar("calendar", holidayCal, true, false);

            String cronExpression = "30/5 * * * * ?"; // 每5s触发任务        
            CronTrigger cronTrigger = new CronTrigger("cronTrigger", 
                    Scheduler.DEFAULT_GROUP, cronExpression);

            cronTrigger.setCalendarName("calendar");

            scheduler.scheduleJob(jobDetail, cronTrigger);

            scheduler.start();
        }

    }
     
     

     JobStore: 任务持久化


    Quartz支持任务持久化,这可以让你在运行时增加任务或者对现存的任务进行修改,并为后续任务的执行持久化这些变更和增加的部分。中心概念是JobStore接口。默认的是RAMJobStore。
     
    初窥Quartz - 紫龍劍 - 倚天万里须长剑
     

    配置文件


    上述没有用到任何的配置文件。Quartz支持配置文件,它的好处是比编写代码简单,且修改后不需要重新编译源码。
     
    >> 配置quartz.properties特性文件
     
    quartz.properties文件定义了Quartz应用运行时行为,还包含了许多能控制Quartz运转的属性。它应放在工程的classpath中。
     
    代码清单5:quartz.properties
    #============================================================================  
    # Configure Main Scheduler Properties  
    #============================================================================

    # 实例名
    org.quartz.scheduler.instanceName = QuartzScheduler 
    # 实例ID
    org.quartz.scheduler.instanceId = AUTO

    #============================================================================
    # Configure ThreadPool  
    #============================================================================
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    # 线程个数
    org.quartz.threadPool.threadCount = 3
    org.quartz.threadPool.threadPriority = 5

    #============================================================================
    # Configure JobStore  
    #============================================================================
    org.quartz.jobStore.misfireThreshold = 60000
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

    #============================================================================
    # Configure Plugins 
    #============================================================================
    org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
    # org.quartz.plugins.xml.JobInitializationPlugin是Quartz自带的插件,
    # 默认时,这个插件会在 classpath 中搜索名为 quartz_jobs.xml 
    # 的文件并从中加载 Job 和 Trigger 信息
    # v1.8之前用JobInitializationPlugin
    #org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
    org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
    org.quartz.plugin.jobInitializer.fileNames = quartz_jobs.xml
    org.quartz.plugin.jobInitializer.failOnFileNotFound = true
    org.quartz.plugin.jobInitializer.scanInterval =10
    org.quartz.plugin.jobInitializer.wrapInUserTransaction = false

    # 关闭quartz新版本检测功能
    org.quartz.scheduler.skipUpdateCheck = true
     
    >> 配置quartz_jobs.xml文件
     
    在配置quart_jobs.xml时,遇到一个问题:
    Exception in thread "main" org.quartz.SchedulerException: SchedulerPlugin class'org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin;' couldnot be instantiated.
     
    因为quartz从版本1.8开始,配置文件有所改动,以前quartz自带的插件是JobInitializationPlugin,而1.8中是XMLSchedulingDataProcessorPlugin. xml schema亦有所改变,难道是改变后配置不对?错误提示是插件类找不到,jar包也都加入到工程了啊。最后终于发现,在quartz.properties特性文件中配置插件行最后多打了个分号。原来是一个多余的分号引发的错误!
     
    下面是新的xml配置文件格式示例。
     
    代码清单6:quartz_jobs.xml格式 

    <?xmlversion="1.0"encoding="UTF-8"?> 

    <job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" 

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

       xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.ogr/xml/job_scheduling_data_1_8.xsd" 

       version="1.8"

       <pre-processing-commands> 

           <!--在执行作业和触犯器之前执行的命令--> 

           <delete-jobs-in-group>*</delete-jobs-in-group> 

           <!--删除标示组中的所有作业,如果是“*”,则删除所有组中的作业,同时也会删除与作业有关的触犯器 --> 

           <delete-triggers-in-group>*</delete-triggers-in-group> 

           <!--删除标示组中的所有触犯器,如果是“*”,则删除所有组中的触发器 --> 

           <delete-job> 

               <!--删除指定的作业,同时也会删除与它关联的触犯器 --> 

               <name></name> 

               <group></group> 

           </delete-job> 

           <delete-trigger> 

               <!--删除指定的触犯器 --> 

               <name></name> 

               <group></group> 

           </delete-trigger> 

       </pre-processing-commands> 

     

       <processing-directives> 

           <!--在计划作业和触发器是应遵循的命令和原则 --> 

           <overwrite-existing-data>true or false</overwrite-existing-data> 

           <!--是否复写已经存在的任务计划数据,如果为false并且ingore-duplicates非false,那么文件中同名的触发器或作业将会继续存在,则会产生错误--> 

           <ignore-duplicates>true or false</ignore-duplicates> 

           <!--如果为true,计划中的任何同名的作业/触发器将会被忽略,不会产生错误--> 

       </processing-directives> 

     

       <schedule> 

           <job> 

               <name>JobName</name> 

               <group>JobGroup</group> 

               <description></description> 

               <job-class></job-class> 

               <job-listener-ref></job-listener-ref> 

               <!-- volatility,durability,recover必须按顺序设定 --> 

               <volatility></volatility> 

               <durability></durability> 

               <recover></recover> 

               <job-data-map> 

                   <!-- entry可以设定多个--> 

                   <entry> 

                       <key></key> 

                       <value></value> 

                   </entry> 

               </job-data-map> 

           </job> 

           <trigger> 

               <!-- Trigger分为simple,crondate-interval三种类型,一个trigger中只能指定一种类型--> 

               <simple> 

                   <name></name> 

                   <group></group> 

                   <description></description> 

                   <job-name></job-name> 

                   <job-group></job-group> 

                   <calendar-name></calendar-name> 

                   <volatility></volatility> 

                   <job-data-map> 

                       <entry> 

                           <key></key> 

                           <value></value> 

                       </entry> 

                   </job-data-map> 

                   <start-time></start-time> 

                   <end-time></end-time> 

                   <misfire-instruction></misfire-instruction> 

                   <repeat-count></repeat-count> 

                   <repeat-interval></repeat-interval> 

               </simple> 

               <cron> 

                   <name></name> 

                   <group></group> 

                   <description></description> 

                   <job-name></job-name> 

                   <job-group></job-group> 

                   <calendar-name></calendar-name> 

                   <volatility></volatility> 

                   <job-data-map> 

                       <entry> 

                           <key></key> 

                           <value></value> 

                       </entry> 

                   </job-data-map> 

                   <start-time></start-time> 

                   <end-time></end-time> 

                   <misfire-instruction></misfire-instruction> 

                   <cron-expression></cron-expression> 

                   <time-zone></time-zone> 

               </cron> 

               <date-interval> 

                   <name></name> 

                   <group></group> 

                   <description></description> 

                   <job-name></job-name> 

                   <job-group></job-group> 

                   <calendar-name></calendar-name> 

                   <volatility></volatility> 

                   <job-data-map> 

                       <entry> 

                           <key></key> 

                           <value></value> 

                       </entry> 

                   </job-data-map> 

                   <start-time></start-time> 

                   <end-time></end-time> 

                   <misfire-instruction></misfire-instruction> 

                   <repeat-interval></repeat-interval> 

                   <repeat-interval-unit></repeat-interval-unit> 

               </date-interval> 

           </trigger> 

       </schedule> 

    </job-scheduling-data>

     

     
    代码清单7:quartz_jobs.xml示例

    <?xmlversion="1.0"encoding="UTF-8"?>  

    <job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" 

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

       xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd" 

       version="1.8">  

          

       <pre-processing-commands>  

           <delete-jobs-in-group>*</delete-jobs-in-group> <!-- clear all jobs in scheduler -->  

           <delete-triggers-in-group>*</delete-triggers-in-group><!-- clear all triggers in scheduler -->  

       </pre-processing-commands>  

          

       <processing-directives>  

           <overwrite-existing-data>true</overwrite-existing-data>  

           <ignore-duplicates>false</ignore-duplicates>   

       </processing-directives>  

          

       <schedule>  

           <job>  

               <name>helloQuartzJob</name>  

               <group>DEFAULT</group>  

               <description>简单的quartz使用</description>  

               <job-class>HelloQuartzJob</job-class>  

               <volatility>false</volatility>  

               <durability>true</durability>  

               <recover>false</recover>  

           </job>  

           <trigger>  

           <cron>

                    <name>trigger</name>     

                  <group>DEFAULT</group>     

                  <job-name>helloQuartzJob</job-name>     

                  <job-group>DEFAULT</job-group> 

                 <cron-expression>30/5 * * * * ?</cron-expression>

           </cron>   

           </trigger>

       </schedule>      

    </job-scheduling-data>

     
    代码清单8:Quartz任务调度
     
    public class HelloQuartzScheduling {
        
        public static void main(String[] args) 
           throws SchedulerException, ParseException {
           
           SchedulerFactory schedulerFactory = new StdSchedulerFactory();
           Scheduler scheduler = schedulerFactory.getScheduler();
           
           scheduler.start();              
        }   
    }

     

     

    这里遇到个问题,提示错误:

    Exception in thread "main" Java.lang.NoClassDefFoundError: javax/transaction/UserTransaction

     

    是由于缺少jta.jar,google出的结果是在quartz发行包的/lib中有此jar包,但是在1.8中没有找到。下载quartz 1.7中,也没有找到,因此,在网上搜一个jta.jar包放置过程classpath中,然后编译运行,ok.

  • 相关阅读:
    CentOS下crontab的定时任务不能执行 行 x :xxxx:未找到命令
    linux用yum安装mysql报错:failure: repodata/repomd.xml from googlechrome: [Errno 256] No more mirrors to try.
    xargs 原理&使用
    关于思科的boss 杜家滨 (转) 采访
    牛气 小米手机专业拆解
    (!)26年间半导体10强回顾 仅INTEL、TI、TOSHIBA保持10大之列
    b.索引 :都是关于 树的 from july
    没事的时候 读读公司的文化 intel 篇
    看了新闻,思科研发中心 没有成都的。。。
    有趣的圣诞节 库的打包
  • 原文地址:https://www.cnblogs.com/panxuejun/p/7007999.html
Copyright © 2011-2022 走看看