Quartz-JobDataMap 参数传递

简介: Quartz-JobDataMap 参数传递

20191223202217702.png

概述


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


JobDataMap


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

我们来温习下纯Quartz的写法

// 具体任务 JobDetail
JobDetail 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.141
Instance group1.job1 of DumbJob says: Hello World!, and val is: 3.141

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

// 具体任务 JobDetail
JobDetail 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,年龄:24
Instance group1.job1,姓名:artisan,年龄:24
Instance 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
@DisallowConcurrentExecution
public 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 ThreadExecutor
INFO  SimpleThreadPool - Job execution threads will use class loader of thread: main
INFO  SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
INFO  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.3
ERROR JobStateExample - 任务key: group1.job1,执行运行时间: 2017-11-13 10:29:40,触发器重复执行次数: 4,触发器执行时间: 10秒
ERROR 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非静态变量值: 1
INFO  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


相关文章
|
3天前
|
人工智能 自然语言处理 Shell
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
仅用3分钟,百炼调用满血版Deepseek-r1 API,享受百万免费Token。阿里云提供零门槛、快速部署的解决方案,支持云控制台和Cloud Shell两种方式,操作简便。Deepseek-r1满血版在推理能力上表现出色,尤其擅长数学、代码和自然语言处理任务,使用过程中无卡顿,体验丝滑。结合Chatbox工具,用户可轻松掌控模型,提升工作效率。阿里云大模型服务平台百炼不仅速度快,还确保数据安全,值得信赖。
129310 24
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
|
5天前
|
人工智能 API 网络安全
用DeepSeek,就在阿里云!四种方式助您快速使用 DeepSeek-R1 满血版!更有内部实战指导!
DeepSeek自发布以来,凭借卓越的技术性能和开源策略迅速吸引了全球关注。DeepSeek-R1作为系列中的佼佼者,在多个基准测试中超越现有顶尖模型,展现了强大的推理能力。然而,由于其爆火及受到黑客攻击,官网使用受限,影响用户体验。为解决这一问题,阿里云提供了多种解决方案。
16205 37
|
13天前
|
机器学习/深度学习 人工智能 自然语言处理
PAI Model Gallery 支持云上一键部署 DeepSeek-V3、DeepSeek-R1 系列模型
DeepSeek 系列模型以其卓越性能在全球范围内备受瞩目,多次评测中表现优异,性能接近甚至超越国际顶尖闭源模型(如OpenAI的GPT-4、Claude-3.5-Sonnet等)。企业用户和开发者可使用 PAI 平台一键部署 DeepSeek 系列模型,实现 DeepSeek 系列模型与现有业务的高效融合。
|
4天前
|
并行计算 PyTorch 算法框架/工具
本地部署DeepSeek模型
要在本地部署DeepSeek模型,需准备Linux(推荐Ubuntu 20.04+)或兼容的Windows/macOS环境,配备NVIDIA GPU(建议RTX 3060+)。安装Python 3.8+、PyTorch/TensorFlow等依赖,并通过官方渠道下载模型文件。配置模型后,编写推理脚本进行测试,可选使用FastAPI服务化部署或Docker容器化。注意资源监控和许可协议。
1208 8
|
13天前
|
人工智能 搜索推荐 Docker
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
DeepSeek R1 + LobeChat + Ollama:快速本地部署模型,创建个性化 AI 助手
3349 117
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
|
8天前
|
人工智能 自然语言处理 API
DeepSeek全尺寸模型上线阿里云百炼!
阿里云百炼平台近日上线了DeepSeek-V3、DeepSeek-R1及其蒸馏版本等六款全尺寸AI模型,参数量达671B,提供高达100万免费tokens。这些模型在数学、代码、自然语言推理等任务上表现出色,支持灵活调用和经济高效的解决方案,助力开发者和企业加速创新与数字化转型。示例代码展示了如何通过API使用DeepSeek-R1模型进行推理,用户可轻松获取思考过程和最终答案。
|
5天前
|
人工智能 自然语言处理 程序员
如何在通义灵码里用上DeepSeek-V3 和 DeepSeek-R1 满血版671B模型?
除了 AI 程序员的重磅上线外,近期通义灵码能力再升级全新上线模型选择功能,目前已经支持 Qwen2.5、DeepSeek-V3 和 R1系列模型,用户可以在 VSCode 和 JetBrains 里搜索并下载最新通义灵码插件,在输入框里选择模型,即可轻松切换模型。
865 14
|
12天前
|
API 开发工具 Python
阿里云PAI部署DeepSeek及调用
本文介绍如何在阿里云PAI EAS上部署DeepSeek模型,涵盖7B模型的部署、SDK和API调用。7B模型只需一张A10显卡,部署时间约10分钟。文章详细展示了模型信息查看、在线调试及通过OpenAI SDK和Python Requests进行调用的步骤,并附有测试结果和参考文档链接。
1887 9
阿里云PAI部署DeepSeek及调用
|
9天前
|
人工智能 数据可视化 Linux
【保姆级教程】3步搞定DeepSeek本地部署
DeepSeek在2025年春节期间突然爆火出圈。在目前DeepSeek的网站中,极不稳定,总是服务器繁忙,这时候本地部署就可以有效规避问题。本文以最浅显易懂的方式带读者一起完成DeepSeek-r1大模型的本地部署。
|
11天前
|
缓存 自然语言处理 安全
快速调用 Deepseek API!【超详细教程】
Deepseek 强大的功能,在本教程中,将指导您如何获取 DeepSeek API 密钥,并演示如何使用该密钥调用 DeepSeek API 以进行调试。

热门文章

最新文章