Quartz-JobDataMap 参数传递

来源:互联网 发布:厨娘物语的淘宝店好 编辑:程序博客网 时间:2024/05/22 13:06

  • 概述
  • JobDataMap
  • Xml 配置方式的值的传递
  • Quartz官方示例
  • Job的状态与并发
  • 其它属性
  • JobExecutionException
  • 示例源码

概述

我们在Quartz-Job 详解中,讲解了纯Quartz的参数传递,这里我们将通过与Spring结合的方式再次讲解一下Quartz中的参数传递。


JobDataMap

JobDataMap可用于保存任何数量的(可序列化的)数据对象,我们希望在执行时可以将其提供给作业实例。JobDataMap是Java Map接口的一个实现,并且有一些用于存储和检索原始类型的数据的方便方法。

我们来温习下纯Quartz的写法

// 具体任务 JobDetailJobDetail job = JobBuilder.newJob(HelloJob.class)        .withIdentity("job1", "group1")        .usingJobData("jobSays", "Hello World!")        .usingJobData("myFloatValue", 3.141f)        .build();

HelloJob如下

/** * 具体执行的任务 */public class HelloJob implements Job {    @Override    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.out.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);    }}

运行结果

Instance group1.job1 of DumbJob says: Hello World!, and val is: 3.141Instance group1.job1 of DumbJob says: Hello World!, and val is: 3.141

如果在Job类中定义与JobDataMap中键值一致的set和get方法,那么Quartz会自动将这些属性注入。如:

// 具体任务 JobDetailJobDetail job = JobBuilder.newJob(HelloJob.class)    .withIdentity("job1", "group1")    .usingJobData("name", "artisan")    .usingJobData("age", 24).build();

HelloJob

import org.quartz.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * 具体执行的任务 */public class HelloJob implements Job {    private String name;    private int age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public void execute(JobExecutionContext context) throws JobExecutionException {        JobKey key = context.getJobDetail().getKey();        System.out.println("Instance " + key + ",姓名:" + name + ",年龄:" + age);    }}

运行结果

Instance group1.job1,姓名:artisan,年龄:24Instance group1.job1,姓名:artisan,年龄:24Instance group1.job1,姓名:artisan,年龄:24

另外Trigger中也可以设置JobDataMap属性,这是为了在多个Trigger中使用相同的Job。

JobExecutionContext 将会合并JobDetail与Trigger的JobDataMap,如果其中属性名相同,后者将覆盖前者。

可以使用JobExecutionContext.getMergedJobDataMap()方法来获取合并后的JobDataMap。


Xml 配置方式的值的传递

在spring中,如果HelloJob的方法有参数,那么需要指定一些设定才可以,否则会在运行时有NoSuchMethodException异常发生。

简单示例

public class HelloJob {    public void execute(String args){        System.out.println("------ " + args + "------ ");    }}

xml配置

<!-- 配置JobDetail --><bean id="springQtzJobMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">    <!-- 执行目标job -->    <property name="targetObject" ref="helloJob"></property>    <!-- 要执行的方法 -->    <property name="targetMethod" value="execute"></property>    <!-- 设置参数-->    <property name="arguments" value="artisan"></property></bean>

增加一个arguments的变量,设置一个value即可,如果你点进去观察源代码,会发现,它其实是一个 Object[] 类型的参数

执行结果

------ artisan------ ------ artisan------

如果你想传递2个参数,示例如下

public void execute(String name, int age) {    System.out.println("------ " + name + ":" + age + "------ ");}
<!-- 设置参数--><property name="arguments">   <list>       <value>artisan</value>       <value>23</value>   </list></property>

当然,我们也可以传递Map,Set,JavaBean对象等等,这里只是抛砖引玉。


Quartz官方示例

第4个案例

http://www.quartz-scheduler.org/documentation/quartz-2.2.x/examples/Example4.html

示例演示了静态变量和非静态变量的修改,只有静态成员才能改变

package com.xgj.quartz.quartzItself.jobDataMapOfficalDemo;import java.text.SimpleDateFormat;import java.util.Date;import org.quartz.DisallowConcurrentExecution;import org.quartz.Job;import org.quartz.JobDataMap;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.quartz.JobKey;import org.quartz.PersistJobDataAfterExecution;@PersistJobDataAfterExecution@DisallowConcurrentExecutionpublic class ColorJob implements Job {    public static final String FAVORITE_COLOR = "favorite color";    public static final String EXECUTION_COUNT = "count";    // 由于Quartz会在每次执行时重新实例化一个类,因此成员非静态成员变量不能用于维护状态!    private int _counter = 1;    public void execute(JobExecutionContext context)            throws JobExecutionException {        JobKey jobKey = context.getJobDetail().getKey();        JobDataMap data = context.getJobDetail().getJobDataMap();        String favoriteColor = data.getString(FAVORITE_COLOR);        int count = data.getInt(EXECUTION_COUNT);        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");        System.out.println("任务Key: " + jobKey + " ,执行时间:  "                + sdf.format(new Date()) + "\n" + "  传递参数(favorite color): "                + favoriteColor + "\n" + "  传递参数(count):  " + count + "\n"                + "  ColorJob非静态变量值: " + _counter + "\n");        count++;        data.put(EXECUTION_COUNT, count);        data.put(FAVORITE_COLOR, "黄色");        _counter++;    }}
package com.xgj.quartz.quartzItself.jobDataMapOfficalDemo;import static org.quartz.DateBuilder.nextGivenSecondDate;import static org.quartz.JobBuilder.newJob;import static org.quartz.SimpleScheduleBuilder.simpleSchedule;import static org.quartz.TriggerBuilder.newTrigger;import java.text.SimpleDateFormat;import java.util.Date;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.quartz.SchedulerFactory;import org.quartz.SchedulerMetaData;import org.quartz.SimpleTrigger;import org.quartz.impl.StdSchedulerFactory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class JobStateExample {    public void run() throws Exception {        Logger log = LoggerFactory.getLogger(JobStateExample.class);        SchedulerFactory sf = new StdSchedulerFactory();        Scheduler sched = sf.getScheduler();        // 在当前时间10秒后运行        Date startTime = nextGivenSecondDate(null, 10);        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");        // 通过过JobDetail封装ColorJob,同时指定Job在Scheduler中所属组及名称,这里,组名为group1,而名称为job1。        JobDetail job1 = newJob(ColorJob.class).withIdentity("job1", "group1")                .build();        // 创建一个SimpleTrigger实例,指定该Trigger在Scheduler中所属组及名称。        // 接着设置调度的时间规则.当前时间10秒后运行,每10秒运行一次,共运行4次        SimpleTrigger trigger1 = newTrigger()                .withIdentity("trigger1", "group1")                .startAt(startTime)                .withSchedule(                        simpleSchedule().withIntervalInSeconds(10)                                .withRepeatCount(4)).build();        // 将参数传递入任务的数据Map中        job1.getJobDataMap().put(ColorJob.FAVORITE_COLOR, "绿色");        job1.getJobDataMap().put(ColorJob.EXECUTION_COUNT, 1);        // 注册并进行调度        Date scheduleTime1 = sched.scheduleJob(job1, trigger1);        log.error("任务key: " + job1.getKey() + ",执行运行时间: "                + sdf.format(scheduleTime1) + ",触发器重复执行次数: "                + trigger1.getRepeatCount() + ",触发器执行时间: "                + trigger1.getRepeatInterval() / 1000 + "秒");        // 第二个任务        JobDetail job2 = newJob(ColorJob.class).withIdentity("job2", "group1")                .build();        SimpleTrigger trigger2 = newTrigger()                .withIdentity("trigger2", "group1")                .startAt(startTime)                .withSchedule(                        simpleSchedule().withIntervalInSeconds(10)                                .withRepeatCount(4)).build();        // 传递数据        job2.getJobDataMap().put(ColorJob.FAVORITE_COLOR, "红色");        job2.getJobDataMap().put(ColorJob.EXECUTION_COUNT, 1);        Date scheduleTime2 = sched.scheduleJob(job2, trigger2);        log.error("第二个任务key: " + job2.getKey().toString() + ",执行运行时间: "                + sdf.format(scheduleTime2) + ",触发器重复执行次数: "                + trigger2.getRepeatCount() + ",触发器执行时间: "                + trigger2.getRepeatInterval() / 1000 + "秒");        // 调度器启动        sched.start();        try {            Thread.sleep(60L * 1000L);        } catch (Exception e) {        }        // 调度器停止        sched.shutdown(true);        SchedulerMetaData metaData = sched.getMetaData();        log.error("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");    }    public static void main(String[] args) throws Exception {        JobStateExample example = new JobStateExample();        example.run();    }}

执行结果如下

INFO  StdSchedulerFactory - Using default implementation for ThreadExecutorINFO  SimpleThreadPool - Job execution threads will use class loader of thread: mainINFO  SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImplINFO  QuartzScheduler - Quartz Scheduler v.2.2.3 created.INFO  RAMJobStore - RAMJobStore initialized.INFO  QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.3) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.  NOT STARTED.  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.INFO  StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'INFO  StdSchedulerFactory - Quartz scheduler version: 2.2.3ERROR JobStateExample - 任务key: group1.job1,执行运行时间: 2017-11-13 10:29:40,触发器重复执行次数: 4,触发器执行时间: 10ERROR JobStateExample - 第二个任务key: group1.job2,执行运行时间: 2017-11-13 10:29:40,触发器重复执行次数: 4,触发器执行时间: 10秒INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.任务Key: group1.job2 ,执行时间:  2017-11-13 10:29:40  传递参数(favorite color): 红色  传递参数(count):  1  ColorJob非静态变量值: 1任务Key: group1.job1 ,执行时间:  2017-11-13 10:29:40  传递参数(favorite color): 绿色  传递参数(count):  1  ColorJob非静态变量值: 1任务Key: group1.job1 ,执行时间:  2017-11-13 10:29:50  传递参数(favorite color): 黄色  传递参数(count):  2  ColorJob非静态变量值: 1任务Key: group1.job2 ,执行时间:  2017-11-13 10:29:50  传递参数(favorite color): 黄色  传递参数(count):  2  ColorJob非静态变量值: 1任务Key: group1.job1 ,执行时间:  2017-11-13 10:30:00  传递参数(favorite color): 黄色  传递参数(count):  3  ColorJob非静态变量值: 1任务Key: group1.job2 ,执行时间:  2017-11-13 10:30:00  传递参数(favorite color): 黄色  传递参数(count):  3  ColorJob非静态变量值: 1任务Key: group1.job1 ,执行时间:  2017-11-13 10:30:10  传递参数(favorite color): 黄色  传递参数(count):  4  ColorJob非静态变量值: 1任务Key: group1.job2 ,执行时间:  2017-11-13 10:30:10  传递参数(favorite color): 黄色  传递参数(count):  4  ColorJob非静态变量值: 1任务Key: group1.job1 ,执行时间:  2017-11-13 10:30:20  传递参数(favorite color): 黄色  传递参数(count):  5  ColorJob非静态变量值: 1任务Key: group1.job2 ,执行时间:  2017-11-13 10:30:20  传递参数(favorite color): 黄色  传递参数(count):  5  ColorJob非静态变量值: 1INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.ERROR JobStateExample - Executed 10 jobs.

Job的状态与并发

@DisallowConcurrentExecution:同一时间将只有一个Job实例被执行。

@PersistJobDataAfterExecution:在Job被执行结束后,将会更新JobDataMap,这样下次Job执行后就会使用新的值而不是初始值。 上面的示例中,如果不用此注解,成员变量的值下次调用也不会有改变。

如果使用@PersistJobDataAfterExecution注解,推荐也使用@DisallowConcurrentExecution注解,这是为了避免并发问题导致数据紊乱。


其它属性

Durability,持久性;如果Job是非持久性的,一旦没有Trigger与其相关联,它就会从Scheduler中被删除。也就是说Job的生命周期和其Trigger是关联的。

RequestsRecovery,如果为true,那么在Scheduler异常中止或者系统异常关闭后,当Scheduler重启后,Job会被重新执行。


JobExecutionException

execute()方法只允许抛出JobExecutionException异常


示例源码

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster