任务调度之Quartz

目录

                  一、认识  Quartz

二、使用Quartz(maven版)

三、理解这家伙

四、附录


一、认识  Quartz

Quartz是一个轻量级的,通过配置文件的来配置并且具有容错能力的任务调度框架。(容错能力指的是当你重启程序的时候定时任务不会丢失)。

         拥有主接口Schedule主要负责安排任务,取消任务,开启任务,停止任务。

         使用Quartz的时候要实现job接口?Job接口里面有一个execute()方法。

         当组件实现TriggerListener或者JobListenter就可以在到达定时任务的时候通知想要通知的人。

         存储空间的大小(RAM的数量和磁盘的大小)是限制Job和Trigger的存储和监听数量的大小。

          SimpTrigger使用在任何毫秒级时间内,指定多久执行一次,可以每N秒执行一次,与当天的时刻无关。

         ConTrigger 可以指定当天的某时刻执行,按照“公历”时间来计算,可以指定一天中的时间触发,然后计算下一次触发的时间。

 二、使用Quartz(maven版)

        1、在官网http://www.quartz-scheduler.org/downloads/下载需要的版本jar包(密码:6znr),在当前服务的pom.xml配置

        
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>

2、在目录src/main/resources目录放置quartz.properties文件并配置

//设置调度程序scheduler的名称为MyScheduler
org.quartz.scheduler.instanceName=XXXScheduler

//线程里设置了3个线程,意味着最多同时运行4个job
org.quartz.threadPool.threadCount=4

/**指定为RAMJobStore,表示所有Quartz的数据,
包括jobDetail、trigger等均运行在内存中(而不是数据库中)。
 如果你想Quartz使用你的数据库,
还是建议你在使用数据库配置之前使用RAMJobStore进行工作。
通过使用一个数据库,你可以打开一个全新的维度,
但在这之前,建议你使用RAMJobStore。
*/
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore

org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool


ADD_NEW_COMPANY_USER_JUDGE_JOB_CRON=0 */5 * * * ?

3、编写一个job类,需要实现org.quartz.Job接口

public class XXXJob implements Job{
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
         
         //要执行的操作
         System.out.println("现在是北京时间:" + DateTimeHelper.formatTime(System.currentTimeMillis()) + " - helloJob任务执行");
    }
}

4、使用job、trigger、schedule调用定时任务

public class TestSchedule extends HttpServlet {

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

        /*ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(setCommand(),getTime(),5, TimeUnit.SECONDS);
       */
        Scheduler  scheduler  = StdSchedulerFactory.getDefaultScheduler();
        System.out.println("scheduleName = " + scheduler.getSchedulerName());
        /** 重要:
         *  定义一个job,并绑定到我们自定义的HelloJob的class对象
         *  这里并不会马上创建一个HelloJob实例,实例创建是在scheduler安排任务触发执行时创建的
         *  这种机制也为后面使用Spring集成提供了便利
         */

        JobDetail job = newJob(XXXJob.class)
                .withIdentity("job1", "group1")
                .build();


        Trigger trigger = newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())
                .build();
        //告诉quartz使用定义的触发器trigger安排执行任务job
        scheduler.scheduleJob(job,trigger);
        //启动任务调度程序,内部机制是线程的启动
        scheduler.start();
        //关闭任务调度程序,如果不关闭,调度程序schedule会一直运行着

        //scheduler.shutdown();
    }

使用CronTrigger来指定某时间进行批跑

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

        JobDetail job = newJob(XXXJob.class)
                .withIdentity("job1", "group1")
                .build();


        CronTrigger trigger = (CronTrigger) newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(cronSchedule("0 13 0-22 * * ?"))
                .build();

        scheduler.scheduleJob(job,trigger);

        scheduler.start();

三、理解Quartz这家伙

Scheduler调度任务-执行计划表,一定是通过scheduler.scheduleJob(job,trigger),当他指定的执行时间到了时间(任务触发Trigger)才执行任务。

  1. Scheduler是与任务程序交互的主程序接口
    
    
      StdSchedulerFactory是org.quartz.SchedulerFactory的实现类,
    它是基于Quartz属性文件创建Quartz Scheduler 调度程序的。
    默认情况下是加载当前工作目录下的”quartz.properties”属性文件。
    如果加载失败就会默认的加载org.quartz文件下面的”quartz.properties”属性文件。
    你可以下载JD-GUI反编译工具打开quartz.jar。
    当没有指定属性配置文件的话就会默认加载 DefaultQuartzScheduler
    
    org.quartz.scheduler.instanceName: DefaultQuartzScheduler
    org.quartz.scheduler.rmi.export: false
    org.quartz.scheduler.rmi.proxy: false
    org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
    org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
    org.quartz.threadPool.threadCount: 10
    org.quartz.threadPool.threadPriority: 5
    org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
    org.quartz.jobStore.misfireThreshold: 60000
    org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
    
        
      SchedulerFactory调用程序工场创建了Scheduler实例,而Scheduler调用程序。
    创建的Scheduler是处于等待状态,在指定任务时间之前调用了Scheduler.start()来启用调度程序,
    才能够执行定时任务。其中shudow()方法用来关闭,而isShutDown()可以用来判断是否关闭。
    通过Scheduler的scheduleJob(…)方法的几个重载方法将任务纳入调度程序中。
    使用scheduleJob(JobDetail jobDetail, Trigger trigger)来将定时任务安排进调度计划中。
    Scheduler维护了JobDetail和Trigger注册表,在Scheduler注册过的job,
    当定时任务触发时间到了,就会有调度程序去执行这个任务的job。
    
    stdSchedulerFactory是是实现类,基于Quartz的配置文件创建Scheduler调度程序
    
    
  2. Job是在未来时间内能被任务调度的时间类(上面Job就是这个东西啦~)
  3.    上面的代码 job是由JobFactor来创建的,你可以看见它的导入包为org.quartz.JobBuilder.*。
         JobDetail job = newJob(XXXJob.class)
                    .withIdentity("job1", "group1")
                    .build();
        在创建JobDetail的时候,将要执行的job的类名传给了JobDetail,
        所以scheduler就知道了要执行何种类型的job,然后每次当scheduler执行job时,
        在调用其execute(…)方法之前会创建该类的一个新的实例,
        执行完毕,对该实例的引用就被丢弃了,实例会被垃圾回收。
        当默认使用JobFactory的时候,Job是一定要有一个默认的构造函数的,
        并且其类不定义有状态的数据属性,因为数据会在执行的时候不会保留.
     

    JobDetail是用来定义定时任务的实例(为newJob()~~)

  4. JobBuilder 是用于声明一个任务实例,也可以定义关于该任务的详情比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务。

    
    JobDetail实例是通过JobBuilder类创建。
    导入该类下的所有静态方法:
    import static org.quartz.JobBuilder.*;
    
    JobDetail的对象的一部分JobDataMap,可以用来增加属性和配置,在Job实例多次被执行的时候跟踪Job
    JobDataMap可以包含不限量的(序列化)数据对象,在job执行实例的时候,可以使用其中的数据。
    
    JobDetail job = newJob(DumbJob.class)
          .withIdentity("myJob", "group1") // name "myJob", group "group1"
          .usingJobData("jobSays", "Hello World!")
          .usingJobData("myFloatValue", 3.141f)
          .build();
    
    public class DumbJob implements Job {
    
            public DumbJob() {
            }
    
            public void execute(JobExecutionContext context)
                throws JobExecutionException
            {
                JobKey key = context.getJobDetail().getKey();
    
                JobDataMap dataMap = context.getJobDetail().getJobDataMap();
    
                String jobSays = dataMap.getString("jobSays");
                float myFloatValue = dataMap.getFloat("myFloatValue");
    
                System.err.println("Instance " + key + " of DumbJob says: " 
                + jobSays + ", and val is: " + myFloatValue);
            }
        }
    
    使用JobStory持久化的存储机制是对JobDataMap不友好的,原因是这会将JobDataMap存储的对象序列化,
    导致类的版本不一致的问题,解决办法是在JobStory或者JobDataMap配置Map仅允许存储基本类型和string类型,
    避免后续的序列化问题。
  5. TriggerBuilder 是触发器创建器,用于创建触发器trigger实例。

  6. Trigger是触发器,表示任务啥时候执行。定义需要执行的任务在那个时间被执行的时间条件。

    
    从导入的包
    import static org.quartz.TriggerBuilder.*;
    import static org.quartz.SimpleScheduleBuilder.*;
    import static org.quartz.DateBuilder.*:
    可以发现:
    SimpleTrigger实例通过TriggerBuilder设置主要的属性,
    通过SimpleScheduleBuilder设置与SimpleTrigger相关的属性,
    DataBuilder使用它可以非常方便地构造基于开始时间(或终止时间)的调度策略。
    
    上面使用了StartNow() 也可以使用StartAt() 指定执行的时间
    trigger = newTrigger()
            .withIdentity("trigger3", "group1")
            .startAt(myTimeToStartFiring)  
            .withSchedule(simpleSchedule()
                .withIntervalInSeconds(10)
                .withRepeatCount(10)) 
            .forJob(myJob)
        // 如果开始时间没有给定就会使用当前时间
        // 十次重发将会产生十一次触发
        // 识别 job 是JobDetail的.build()
       

四、附录

CronTrigger的表达式常用示例:

猜你喜欢

转载自blog.csdn.net/LCF_lxf_ldy/article/details/83003231