zoukankan      html  css  js  c++  java
  • Quartz使用(2)

    quartz的核心接口如下:

    接口 含义
    Scheduler scheduler的主要API接口
    Job 任务实现接口,期望调度器能够执行
    JobDetail 用于定义Job实例
    Trigger 调度器基于特定时间来执行指定任务的组件
    JobBuilder   用于定义、创建JobDetail实例
    TriggerBuilder 用于定义、创建Trigger实例

    1. Scheduler

    一个调度器的生命周期为通过SchedulerFactory创建,直到执行其shutdown()方法。当Scheduler创建之后,可以进行增加、删除及显示任务Job与触发器Trigger,并且执行其他的调度相关的操作,如暂停一个触发器Trigger。需要注意的是,直到调用start()方法时,Scheduler才正式开始执行job和trigger。

    StdSchedulerFactory用于创建Scheduler,其依赖于一系列的属性来决定如何产生Scheduler。可以通过四种途径向StdSchedulerFactory提供属性配置信息。

    1) 通过java.util.Properties实例提供

    package org.ws.quartz.test2;
    
    import java.util.Properties;
    
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.impl.StdSchedulerFactory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SchedulerExample {
        
        private static Logger logger = LoggerFactory.getLogger(SchedulerExample.class);
        
        public static void main(String[] args) {
            // 创建工厂实例
            StdSchedulerFactory factory = new StdSchedulerFactory();
            
            // 创建配置工厂的属性对象
            Properties props = new Properties();
            props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool"); // 线程池定义
            props.put("org.quartz.threadPool.threadCount", "10"); // 默认Scheduler的线程数
            
            try {
                // 使用定义的属性初始化工厂
                factory.initialize(props);
                
                Scheduler scheduler = factory.getScheduler();
                
                scheduler.start();
                logger.info("scheudler started, metadata: "+scheduler.getMetaData());
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }
    View Code

    执行后的结果:

    2017-07-09 15:15:17 [INFO]-[org.ws.quartz.test2.SchedulerExample] scheudler started, metadata: Quartz Scheduler (v2.2.1) 'QuartzScheduler' with instanceId 'NON_CLUSTERED'
      Scheduler class: 'org.quartz.impl.StdScheduler' - running locally.
      Running since: Sun Jul 09 15:15:17 CST 2017
      Not currently in standby mode.
      Number of jobs executed: 0
      Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
      Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
    
      
    View Code

    可以看到对应的配置属性已经生效。

    通过Properties设置工厂属性的缺点在用硬编码,假如需要修改例子中线程数量,将不得不修改代码,然后重新编译。后面几种方法可以解决硬编码的问题。

    2) 通过外部属性文件提供

    使用方法:

    public void initialize(String filename) throws SchedulerException;

    3) 通过含有属性文件内容的java.io.InputStream提供

    使用方法:

    public void initialize(InputStream propertiesStream) throws SchedulerException;

    4) quartz.properties配置文件【推荐

    如果调用无参的initialize方法,StdSchedulerFactory会试图从quartz.properties的文件中加载。quartz.properties相关配置后续文章会介绍,注意quartz.properties的加载顺序为:

    a. 检查System.getProperty("org.quartz.properties")中是否设置其他属性文件名

    b. 如果a未设置,则将会从当前工作目录中加载quartz.properties配置文件

    c. 如果b未找到,则试图从系统的classpath中加载该配置文件。

    Scheduler在生命周期中也可执行其他操作,如查询、设置standby模式、继续执行、停止执行。standby模式会导致Scheduler暂时停止查找Job去执行。standby模式的设置直接使用scheudler.standby()即可。

    Scheduler的停止方法为shutdown()方法,也可以使用有参shutdown(false),其中参数表示是否让当前正在进行的job正常执行完成才停止Scheduler

    2. Job

    Job即为为你执行一个任务的Java类。该任务可以是java编码的任何功能,如使用JavaMail发送邮件、创建远程接口并调用EJB上的方法等。

    Java类仅需要实现org.quartz.job接口,将所需要实现的功能放在其execute方法中。execute方法的定义如下:

    public void execute(JobExecutionContext context) throws JobExecutionException;

    其中JobExecutionContext对象让Job能访问Quartz运行时环境的所有信息和Job本身的明细数据。运行时环境信息包括注册到Scheduler上与该Job相关联的JobDetail和Trigger。

    例:Quartz使用(1) - 初识quartz示例中HelloWordJob获取运行环境时信息如下:

    package org.ws.quartz.test1;
    
    import org.quartz.Job;
    import org.quartz.JobDetail;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class HelloWorldJob implements Job{
        
        private static Logger logger = LoggerFactory.getLogger(HelloWorldJob.class);
        
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            
            logger.info("Hello World");
            
            // 每一个Job都有其自己所属的JobDetail
            JobDetail jobDetail = context.getJobDetail();
            
            // JobDetail的名称和组名
            logger.info("Name and Group: "+jobDetail.getKey());
            
            // 获取Scheduler
            Scheduler scheduler = context.getScheduler();
            try {
                logger.info("Scheduler name: "+scheduler.getSchedulerName());
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
            
            logger.info("job class: "+jobDetail.getJobClass());
            
            // 任务执行的时间
            logger.info("Job fired at "+context.getFireTime());
            
            // 任务下一次执行的时间
            logger.info("Job nexe fire time: "+context.getNextFireTime());
        }
    }
    View Code

    运行结果如下:

    2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] init scheduler componets
      2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] execute scheduler
      2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World
      2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Name and Group: HelloWorld_Group.HelloWorld_Job
      2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Scheduler name: DefaultQuartzScheduler
      2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] job class: class org.ws.quartz.test1.HelloWorldJob
      2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job fired at Sun Jul 09 16:00:59 CST 2017
      2017-07-09 16:00:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job nexe fire time: Sun Jul 09 16:01:09 CST 2017
      2017-07-09 16:01:09 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World
      2017-07-09 16:01:09 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Name and Group: HelloWorld_Group.HelloWorld_Job
      2017-07-09 16:01:09 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Scheduler name: DefaultQuartzScheduler
      2017-07-09 16:01:09 [INFO]-[org.ws.quartz.test1.HelloWorldJob] job class: class org.ws.quartz.test1.HelloWorldJob
      2017-07-09 16:01:09 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job fired at Sun Jul 09 16:01:09 CST 2017
      2017-07-09 16:01:09 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job nexe fire time: Sun Jul 09 16:01:19 CST 2017
      2017-07-09 16:01:19 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World
      2017-07-09 16:01:19 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Name and Group: HelloWorld_Group.HelloWorld_Job
      2017-07-09 16:01:19 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Scheduler name: DefaultQuartzScheduler
      2017-07-09 16:01:19 [INFO]-[org.ws.quartz.test1.HelloWorldJob] job class: class org.ws.quartz.test1.HelloWorldJob
      2017-07-09 16:01:19 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job fired at Sun Jul 09 16:01:19 CST 2017
      2017-07-09 16:01:19 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job nexe fire time: Sun Jul 09 16:01:29 CST 2017
      2017-07-09 16:01:29 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World
      2017-07-09 16:01:29 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Name and Group: HelloWorld_Group.HelloWorld_Job
      2017-07-09 16:01:29 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Scheduler name: DefaultQuartzScheduler
      2017-07-09 16:01:29 [INFO]-[org.ws.quartz.test1.HelloWorldJob] job class: class org.ws.quartz.test1.HelloWorldJob
      2017-07-09 16:01:29 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job fired at Sun Jul 09 16:01:29 CST 2017
      2017-07-09 16:01:29 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job nexe fire time: Sun Jul 09 16:01:39 CST 2017
      2017-07-09 16:01:39 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World
      2017-07-09 16:01:39 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Name and Group: HelloWorld_Group.HelloWorld_Job
      2017-07-09 16:01:39 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Scheduler name: DefaultQuartzScheduler
      2017-07-09 16:01:39 [INFO]-[org.ws.quartz.test1.HelloWorldJob] job class: class org.ws.quartz.test1.HelloWorldJob
      2017-07-09 16:01:39 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job fired at Sun Jul 09 16:01:39 CST 2017
      2017-07-09 16:01:39 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job nexe fire time: Sun Jul 09 16:01:49 CST 2017
      2017-07-09 16:01:49 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World
      2017-07-09 16:01:49 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Name and Group: HelloWorld_Group.HelloWorld_Job
      2017-07-09 16:01:49 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Scheduler name: DefaultQuartzScheduler
      2017-07-09 16:01:49 [INFO]-[org.ws.quartz.test1.HelloWorldJob] job class: class org.ws.quartz.test1.HelloWorldJob
      2017-07-09 16:01:49 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job fired at Sun Jul 09 16:01:49 CST 2017
      2017-07-09 16:01:49 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job nexe fire time: Sun Jul 09 16:01:59 CST 2017
      2017-07-09 16:01:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World
      2017-07-09 16:01:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Name and Group: HelloWorld_Group.HelloWorld_Job
      2017-07-09 16:01:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Scheduler name: DefaultQuartzScheduler
      2017-07-09 16:01:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] job class: class org.ws.quartz.test1.HelloWorldJob
      2017-07-09 16:01:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job fired at Sun Jul 09 16:01:59 CST 2017
      2017-07-09 16:01:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Job nexe fire time: Sun Jul 09 16:02:09 CST 2017
      2017-07-09 16:01:59 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] shut down scheduler
      
    View Code

    3. JobDetail

    3.1 Job简述

    JobDetail是作为Job实例进行定义的,注意部署在Scheduler上的每一个Job只创建一个JobDetail实例。且需要注意的是注册到Scheduler上的不是Job对象,而是JobDetail实例。

    Job 的实例要到该执行它们的时候才会实例化出来。每次 Job 被执行,一个新的 Job 实例会被创建。其中暗含的意思就是你的 Job 不必担心线程安全性,因为同一时刻仅有一个线程去执行给定 Job 类的实例,甚至是并发执行同一 Job 也是如此

    可以使用JobDataMap来定义Job的状态,JobDataMap中可以存入key-value对,这些数据可以在Job实现类中进行传递和访问。这是向你的Job传送配置信息的便捷方法。

    Job 能通过 JobExecutionContext 对象访问 JobDataMap

    例:在Quartz使用(1) - 初识quartz示例中,可以在等待时间修改为20s, SimpleQuartzExample.createJobDetail方法修改为:

    protected JobDetail createJobDetail(){
            return JobBuilder.newJob(HelloWorldJob.class) // 待执行的任务
                    .withIdentity("HelloWorld_Job", "HelloWorld_Group") // 名称与组名组成Scheduler中任务的唯一标识
                    .usingJobData("message", "welcom to study quartz") // 存储Job的状态信息
                    .build(); // 构建
        }
    View Code

    同时HelloWorldJob中的execute方法修改如下:

    public void execute(JobExecutionContext context) throws JobExecutionException {
            logger.info("Hello World, "+context.getJobDetail().getJobDataMap().get("message"));
        }
    View Code

    执行结果:

    2017-07-09 16:17:51 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] init scheduler componets
      2017-07-09 16:17:51 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] execute scheduler
      2017-07-09 16:17:51 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World, welcom to study quartz
      2017-07-09 16:18:01 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World, welcom to study quartz
      2017-07-09 16:18:11 [INFO]-[org.ws.quartz.test1.HelloWorldJob] Hello World, welcom to study quartz
      2017-07-09 16:18:11 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] shut down scheduler
    View Code

     3.2 有状态Job和无状态Job

    有状态的Job可以理解为多次Job调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,而默认的无状态job每次调用时都会创建一个新的JobDataMap

    有状态的Job示例:

    调度主方法:

    package org.ws.quartz.test1;
    
    import org.quartz.JobBuilder;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SimpleScheduleBuilder;
    import org.quartz.Trigger;
    import org.quartz.TriggerBuilder;
    import org.quartz.impl.StdSchedulerFactory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SimpleQuartzExample {
        
        private static Logger logger = LoggerFactory.getLogger(SimpleQuartzExample.class);
        
        public static void main(String[] args) throws SchedulerException, InterruptedException {
            
            SimpleQuartzExample exam = new SimpleQuartzExample();
            
            logger.info("init scheduler componets");
            
            // 创建任务
            JobDetail jobDetail = exam.createJobDetail();
            
            // 创建触发器
            Trigger trigger = exam.createTrigger();
            
            // 创建调度器
            Scheduler scheduler = exam.createScheduler();
    
            // 构建调度任务
            scheduler.scheduleJob(jobDetail, trigger);
            
            logger.info("execute scheduler");
            // 开启调度器
            scheduler.start();
            
            // 一分钟后关闭调度器
            Thread.sleep(20000);
            scheduler.shutdown();
            
            logger.info("shut down scheduler");
        }
    
        protected Scheduler createScheduler() throws SchedulerException{
            return StdSchedulerFactory.getDefaultScheduler(); 
        }
        
        protected JobDetail createJobDetail(){
            return JobBuilder.newJob(HelloWorldJob.class) // 待执行的任务
                    .withIdentity("HelloWorld_Job", "HelloWorld_Group") // 名称与组名组成Scheduler中任务的唯一标识
                    .usingJobData("count", 0) // 将count初始化为0
                    .build(); // 构建
        }
        
        protected Trigger createTrigger(){
            return  TriggerBuilder.newTrigger()
                    .withIdentity("HelloWorld_Trigger", "HelloWorld_Group") // 名称与组名组成Scheduler中触发器的唯一标识
                    .withSchedule(
                            SimpleScheduleBuilder.simpleSchedule() // 创建SimpleTrigger
                            .withIntervalInSeconds(10) // 10秒间隔
                            .repeatForever() // 重复循环
                            ).build(); // 构建
        }
    }
    View Code

    HelloWorldJob方法:

    package org.ws.quartz.test1;
    
    import org.quartz.Job;
    import org.quartz.JobDataMap;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.quartz.PersistJobDataAfterExecution;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    @PersistJobDataAfterExecution
    public class HelloWorldJob implements Job{
        
        private static Logger logger = LoggerFactory.getLogger(HelloWorldJob.class);
        
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
            
            int count = jobDataMap.getInt("count");
            logger.info("count: "+count);
            
            ++count;
            jobDataMap.put("count", count);
        }
    }
    View Code

    执行结果:

    2017-07-09 16:38:55 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] init scheduler componets
      2017-07-09 16:38:55 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] execute scheduler
      2017-07-09 16:38:55 [INFO]-[org.ws.quartz.test1.HelloWorldJob] count: 0
      2017-07-09 16:39:05 [INFO]-[org.ws.quartz.test1.HelloWorldJob] count: 1
      2017-07-09 16:39:15 [INFO]-[org.ws.quartz.test1.HelloWorldJob] count: 2
      2017-07-09 16:39:15 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] shut down scheduler
      
    View Code

    如果不增加@PersistJobDataAfterExecution注解,运行结果为:

    2017-07-09 16:40:58 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] init scheduler componets
      2017-07-09 16:40:59 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] execute scheduler
      2017-07-09 16:40:59 [INFO]-[org.ws.quartz.test1.HelloWorldJob] count: 0
      2017-07-09 16:41:08 [INFO]-[org.ws.quartz.test1.HelloWorldJob] count: 0
      2017-07-09 16:41:18 [INFO]-[org.ws.quartz.test1.HelloWorldJob] count: 0
      2017-07-09 16:41:19 [INFO]-[org.ws.quartz.test1.SimpleQuartzExample] shut down scheduler
    View Code

    可见 @PersistJobDataAfterExecution的作用在于持久化保存在JobDataMap中的传递参数,使得多次执行Job,可以获取传递参数的状态信息。

    3.3 @DisallowConcurrentExecution  

    quartz中另一个常用的注解为@DisallowConcurrentExecution,该注解可以同一个时刻,同一个任务只能执行一次,不能并行执行两个或多个同一任务。但需要注意的是,多个不同的任务是可以同时执行的

     

  • 相关阅读:
    《WCF全面解析》-上册 1-3章 读书笔记
    git上传本地Intellij idea 项目到码云的git仓库中
    Node.js安装及环境配置之Windows篇
    让IntelliJ IDEA支持创建*.vue文件及打开*.vue文件
    maven命令mvn package指定jar包名称
    spring 时间格式化注解@DateTimeFormat和 @JsonFormat
    事务及事务隔离级别
    @RequestBody的使用
    接口jdk1.8与jdk1.9新特性
    Spring AOP无法拦截内部方法调用-- expose-proxy="true"用法
  • 原文地址:https://www.cnblogs.com/mengrennwpu/p/7141986.html
Copyright © 2011-2022 走看看