Quartz传递数据和有无状态Job(三)下

简介: Quartz传递数据和有无状态Job(三)下

三. 传递数据


在主程序中通过建造模式生成 JobDetail 和 Trigger时,可以传递一些数据, 这样在 Job接口里面通过 JobExecutionContext 上下文对象就可以获取该数据, 从而根据这些数据,来执行不同的操作。


JobDetailBuilder 和 TriggerBuilder 通过调用 usingJobData() 方法,来传递数据。


三.一 通过 Map中的 key 传递数据

三.一.一 接口任务

//获取前台传递过来的数据
public class MyJob5 implements Job {
  @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString=sdf.format(new Date());
        //通过 jobExecutionContext 来获取对象
        JobKey jobKey=jobExecutionContext.getJobDetail().getKey();
        System.out.println("名称:"+jobKey.getName());
        //获取JobDetaMap 数据对象集合
       JobDataMap dataMap= jobExecutionContext.getJobDetail().getJobDataMap();
        System.out.println("JobDetail消息:"+dataMap.getString("message"));
        System.out.println("JobDetail数目:"+dataMap.getInt("count"));
        System.out.println("JobDetail无Key:"+dataMap.getString("jobDetail"));
        //获取 Trigger 的集合
        Trigger trigger=jobExecutionContext.getTrigger();
        System.out.println("Trigger名称:"+trigger.getKey().getName());
        //获取Trigger 里面的Map数据
        JobDataMap triggerMap=jobExecutionContext.getTrigger().getJobDataMap();
        System.out.println("Trigger message:"+triggerMap.get("message"));
        System.out.println("Trigger code:"+triggerMap.getInt("code"));
        System.out.println("Trigger 无key:"+triggerMap.getString("trigger"));
        System.out.println("正在备份数据库:"+dateString);
    }
}


三.一.二 主程序

//工作任务中获取信息
public class SchedulerDemo5 {
    public static void main(String[] args) throws  Exception{
      //创建 Scheduler 实例
        Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
        //创建Job
        JobDetail jobDetail= JobBuilder.newJob(MyJob5.class)
                .withIdentity("job1","group1")
                .usingJobData("message","两个蝴蝶飞设置JobDetail 消息")
                .usingJobData("count",207)
                .build();
        //获取相应的信息
        //创建 Trigger
        Trigger trigger= TriggerBuilder.newTrigger()
                .withIdentity("trigger1","group1")
                .startNow()
                .usingJobData("message","两个蝴蝶飞设置Trigger 消息")
                .usingJobData("code",200)
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
                .build();
        //关联一下
        scheduler.scheduleJob(jobDetail,trigger);
        //启动
        scheduler.start();
    }
}


三.一.三 控制台打印

image.png


可以准确地获得 JobDetail和 Trigger传递过来的数据,即使 key相同,也依然可以获取。


如果获取的key不存在的话, 那么显示的是默认值 null值。


注意,此时获取的是 String 字符串

System.out.println("JobDetail无Key:"+dataMap.getString("jobDetail"));


jobDetail这个 key不存在,获取的是 null


但如果是 int类型不存在的话

System.out.println("JobDetail无Key:"+dataMap.getInt("jobDetail"));


那么这个时候,就会报错了。

java.lang.ClassCastException: Identified object is not an Integer.


其对应底层代码是:

public int getInt(String key) {
  //获取值
        Object obj = get(key);
        try {
            if(obj instanceof Integer)
                return ((Integer) obj).intValue();
            return Integer.parseInt((String)obj);
        } catch (Exception e) {
    //不属于 Integer, 抛出异常 
            throw new ClassCastException("Identified object is not an Integer.");
        }
    }

三.二 Job任务通过 setter 方法获取值

在 Job任务里面,定义属性字段,实现相应的setter方法,就可以获取前台传递过来的数据了。


三.二.一 接口任务

//set方法 获取前台传递过来的数据
public class MyJob6 implements Job {
    private String message;
    private int count;
    private int code;
    public void setMessage(String message) {
        this.message = message;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public void setCode(int code) {
        this.code = code;
    }
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString=sdf.format(new Date());
        System.out.println("正在备份数据库:"+dateString);
        //JobDetail 和Trigger 设置相同的key 的话,取出 trigger 里面的值
        System.out.println("输出message:"+message);
        System.out.println("输出count:"+count);
        System.out.println("输出code:"+code);
    }
}


三.二.二 主程序获取

//setter方法 工作任务中获取信息
public class SchedulerDemo6 {
    public static void main(String[] args) throws  Exception{
      //创建 Scheduler 实例
        Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
        //创建Job
        JobDetail jobDetail= JobBuilder.newJob(MyJob6.class)
                .withIdentity("job1","group1")
                .usingJobData("message","两个蝴蝶飞设置JobDetail 消息")
                .usingJobData("count",207)
                .build();
        //获取相应的信息
        //创建 Trigger
        Trigger trigger= TriggerBuilder.newTrigger()
                .withIdentity("trigger1","group1")
                .startNow()
                .usingJobData("message","两个蝴蝶飞设置Trigger 消息")
                .usingJobData("code",200)
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
                .build();
        //关联一下
        scheduler.scheduleJob(jobDetail,trigger);
        //启动
        scheduler.start();
    }
}


三.二.三 控制台打印输出


image.png

通过setter 方法,可以获取前台传递过来的值。


当JobDetail和 Trigger的 key一致时, Job接口中获取到的是 Trigger里面的值,与定义前后顺序无关


四. 有状态和无状态 Job


什么叫做有无状态 Job呢?


简单来说, Job接口里面通过setter方法或者 Map中的key 获取前台传递过来的数据, 能不能把这个数据保存起来呢?


这样,当下一次运行的时候,获取到的值是上一次运行后设置的值,并不是前面通过JobDetail设置过来的值。


如JobDetail 前面传递过来一个 count, 每次执行后 count都加1, 当小于10时,执行什么操作,当>10 &&<20时,执行什么操作,当>20时执行什么操作。 这样的需求也是有的。


从第一部分我们知道, 每一次执行程序,都会重新实例化对象, 每次都是一个新的对象,自然每次都会将属性重新设置,


这个count 数据是不会保存下来的, 是无状态的。


然而,Quartz提供了一个注解 @PersistJobDataAfterExecution, 通过在 Job任务上添加这个注解,

就可以使这个 Job变成有状态的 Job,可以保存这个数据 count。


四.一 演示没有注解,无状态的Job

四.一.一 Job任务

此时,没有注解。

//有无状态Job 设置 
public class MyJob7 implements Job {
    private int count;
    public void setCount(int count) {
        this.count = count;
    }
    public MyJob7(){
      System.out.println("构建对象");
    }
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString=sdf.format(new Date());
        //让数目自增1
        ++ count;
        System.out.println("count:"+count);
        System.out.println("当前对象的地址:"+this.toString());
        jobExecutionContext.getJobDetail().getJobDataMap().put("count",count);
        System.out.println("正在备份数据库:"+dateString);
    }
}


四.一.二 主程序

//有无状态job设置
public class SchedulerDemo7 {
    public static void main(String[] args) throws  Exception{
      //创建 Scheduler 实例
        Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
        //创建Job
        JobDetail jobDetail= JobBuilder.newJob(MyJob7.class)
                .withIdentity("job1","group1")
                .usingJobData("count",0)
                .build();
        //获取相应的信息
        //创建 Trigger
        Trigger trigger= TriggerBuilder.newTrigger()
                .withIdentity("trigger1","group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
                .build();
        //关联一下
        scheduler.scheduleJob(jobDetail,trigger);
        //启动
        scheduler.start();
    }
}

四.一.三 控制台打印输出

image.png


发现,每次得到的count 数目都是1,是无状态的。


四.二 演示有注解,有状态的Job

在 MyJob7 类上添加注解 @PersistJobDataAfterExecution

@PersistJobDataAfterExecution 
//添加注解之后,不会每次都重新实例化JobDataMap
//有无状态Job 设置 
public class MyJob7 implements Job {
}


重新运行程序,控制台打印输出:

image.png



虽然每次都会重新实例化 MyJob7对象,但是 count 这个数据是保存了下来, 成了有状态的Job


如果添加了注解 @PersistJobDataAfterExecution,当重复运行任务时,虽然每一次都会重新实例化Job对象,但并不会每次都重新实例化 JobDataMap, 那么 JobDataMap里面的数据就可以保存下来了。


谢谢您的观看!!!

相关文章
|
8月前
|
消息中间件 存储 Kafka
Flink---11、状态管理(按键分区状态(值状态、列表状态、Map状态、归约状态、聚合状态)算子状态(列表状态、广播状态))
Flink---11、状态管理(按键分区状态(值状态、列表状态、Map状态、归约状态、聚合状态)算子状态(列表状态、广播状态))
|
10月前
quartz(二)动态增删改查停止启用job
quartz(二)动态增删改查停止启用job
37 0
|
XML SQL Java
Flowable 设置任务处理人的四种方式
Flowable 设置任务处理人的四种方式
|
SQL 存储 数据库
Flowable 设置流程变量的四种方式
Flowable 设置流程变量的四种方式
|
Python
FastAPI(35)- 依赖项中使用 yield + Context Manager 上下文管理器
FastAPI(35)- 依赖项中使用 yield + Context Manager 上下文管理器
267 0
|
Java Android开发
JobService源码探究之 onStartJob()里执行耗时逻辑导致Job可能被强制销毁
JobService源码探究之 onStartJob()里执行耗时逻辑导致Job可能被强制销毁
|
前端开发 开发者
介绍有状态组件和无状态组件的区别|学习笔记
快速学习介绍有状态组件和无状态组件的区别
146 0
|
前端开发
介绍有状态组件和无状态组件的区别
介绍有状态组件和无状态组件的区别
|
存储 算法 Unix
bthread源码剖析(四): 通过ParkingLot实现Worker间任务状态同步
通过之前的文章我们知道TaskGroup(以下简称TG)是在死循环等待任务,然后切换栈去执行任务。在当前TG没有任务的时候会进行“工作窃取”窃取其他TG的任务。在没有任务的时候TG会“休眠”,当任务出现的时候被唤醒然后消费。
259 0
|
监控 Java Android开发
【Android 电量优化】JobScheduler 相关源码分析 ( ConnectivityController 底层源码分析 | 构造函数 | 追踪任务更新 | 注册接收者监听连接变化 )
【Android 电量优化】JobScheduler 相关源码分析 ( ConnectivityController 底层源码分析 | 构造函数 | 追踪任务更新 | 注册接收者监听连接变化 )
173 0