1. Quartz的基本介绍
1.1 Quartz的概念
Quartz是OpenSymphony开源组织在job scheduling领域的开源项目(定时任务调度框架),它开源集成到J2EE进二J2SE应用程序,也可以进行单独使用
Quartz任务调度框架的官方定义:
- quartz是一个开源且特性丰富的"任务调度库",那个集成到任何java程序中,小到独立的应用,大到电子商城系统
- quartz能够创建亦简单亦复杂的调度,可以执行甚至上万的任务调度
- 任务job被定义为标准的java组件,能够执行任何需求功能,
- quartz调度框架包含许多企业级的特性,如:AT事物,集群的支持
Quartz的开发应用场景:
- 定时任务的调度
- 循环任务的调度
简而言之Quartz就是基于java开发的任务调度框架
1.2 Quartz的运行环境
Quartz可以在四种环境下运行:
- Quartz可以运行嵌入在另一个独立式应用程序中
- Quartz可以在应用程序服务器(或servlet容器)内被实例化,并参与事物
- Quartz可以做为一个独立的程序运行(其自己的java),可以通过RMI使用
- Quartz可以被实例化,做为独立的项目集群(负载平衡和故障转移功能),用于作业的执行
Quartz使用到的设计模式:
- Builder模式(创建者模式)
- Factory模式(工厂模式)
- 组件模式
-
链式编程
2. Quartz的核心概念与API
2.1 Quartz的核心概念
Quartz的四大核心概念:
1,任务job:
- job就是想要实现的任务类,每一个job必须实现org.quartz.job接口,且只需实现接口定义的execute()方法
2,任务信息JobDetall
- JobDetail实例是在将job加入scheduler时,由客户端程序(你的程序)创建的。它包含job的各种属性设置,以及用于存储job实例状态信息的JobDataMap
3,触发器Trigger:
- Trigger为实现执行任务的触发器,比如你想每周一定时8点进行数据库备份,Trigger将会设置3点进行执行该任务
- Trigger主要包含SimpleTrigger和CronTrigger两种,且有不同的应用场景
4,调度器Scheduler:
- Scheduler为任务的调度器,它会将任务job及触发器trigger两种进行整合,负责Trigger设定时间来执行job
Quartz体系结构图:
2.2 Quartz的常用组件API
以下是Quartz编程API几个重要接口组件:
- Scheduler:用于调度程序交互的主程序接口
- job:预先定义希望在未来时间能够被调度程序执行的任务类
- jobDerail:定义job任务的基本信息,通过JobBuilder类创建
- jobDataMap:可以包含不限量的序列化数据对象,在Job实例执行的时候,可以使用其中的数据;JobDataMap是Java Map接口的实现,额外的增加了一些存取的基本类型方法
- Trigger:触发执行Job,当调度一个job时,外面实例一个触发器调整它们的属性来满足job执行的条件,定义一个任务在什么时候执行和执行次数
- JobBuilder:用于声明一个任务实例,也可以定义关于该任务的详情比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务
- TriggerBuilder:触发器创建器,用于创建触发器trigger实例
- JobListener、TriggerListener、SchedulerListener监听器,用于对组件的监听
3. Quartz初体验
导入maven依赖:
<!--quartz核心包--> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version> </dependency> <!--quartz jo工具包--> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.3.2</version> </dependency>
① 任务类型
public class HelloJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前日期和数据 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateformat = simpleDateFormat.format(date); //执行任务 System.out.println(dateformat+"--数据库备份!!"); } }
② 调度
//1,调度器(Scheduler),从工厂中获取调度实例 Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler(); //2,任务实例(JobDetail) JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//加载任务类 .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称 .build(); //3,触发器(Trigger) SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1")//参数1:触发器名称 参数2:触发器组名称 .startNow()//启动后立即执行触发器 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(7))//每七秒执行重复执行一次 .build(); //Scheduler调度器关联任务实例和触发器,保证触发器定义的条件执行任务实例 defaultScheduler.scheduleJob(jobDetail,trigger); //启动调度器 defaultScheduler.start();
结果:
2022-10-12 16:58:18--数据库备份!! 2022-10-12 16:58:25--数据库备份!! 2022-10-12 16:58:32--数据库备份!! 2022-10-12 16:58:39--数据库备份!!
4. 各组件说明
4.1 Job和JonDetail的说明
Job和JobDetail的作用:
- Job:工作任务调度的接口,任务类需要实现该接口。该接口中定义execute方法,类似于JDK提供的Runable类的run方法。在里面编写业务逻辑
- JobDetail:JobDetail为Job实例类提供了许多属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助obDetail对象来添加Job实例
Job实例在Quartz中的生命周期:
- 每次调度器执行Job时,它在调用execute方法前会创建一个新的Job实例
- 当Job调用完成后,关联的Job对象会被释放,释放的实例会被垃圾回收机制回收
JobDetail的重要属性:
- name:任务名称
- group:任务组
- jobClass:任务对象
- jobDataMap: 可传输数据的集合
JobDetail的常用方法:
- jobDetail.getKey():获取任务类的基本信息,如:name(任务名),group(任务组),class(任务类)
- jobDetail.getJobDataMap():获取JobDataMap
- jobDetail.isDurable():Job没有触发器指向它的时候是否应该继续存储
- jobDetail.requestsRecovery():指示调度器在遇到“恢复”或“故障转移”情况时是否应重新执行作业
- jobDetail.withIdentity():设置任务名称和任务组,如果不指定使用默认任务名和任务组
- jobDetail.newJob():指定任务类,class类型
- jobDetail.usingJobData():给JobDataMap对象赋值
- ……
例1:演示在调度器每次调用Job时都会创建新的job对象
① 在Job中新建构造方法
public class HelloJob implements Job { public HelloJob() { System.out.println("HelloJob被创建"); } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前日期和数据 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateformat = simpleDateFormat.format(date); //执行任务 System.out.println(dateformat+"--数据库备份!!"); } }
调用省略,直接测试:
HelloJob被创建 2022-10-12 17:33:38--数据库备份!! HelloJob被创建 2022-10-12 17:33:45--数据库备份!! HelloJob被创建 2022-10-12 17:33:52--数据库备份!!
例2:测试JobDetail方法
//1,调度器(Scheduler),从工厂中获取调度实例 Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler(); //2,任务实例(JobDetail) JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//加载任务类 .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称 .build(); //获取任务名 System.out.println("任务名:"+jobDetail.getKey().getName()); //获取任务组 System.out.println("任务组:"+jobDetail.getKey().getGroup()); //获取任务类(class类型) System.out.println("任务类:"+jobDetail.getKey().getClass()); //获取JobDataMap System.out.println("任务存储数据map:"+jobDetail.getJobDataMap()); ……省略
测试:
任务名:job1 任务组:group1 任务类:class org.quartz.JobKey 任务存储数据map:org.quartz.JobDataMap@0
4.2 JobExecutionContext说明
JobExecutionContext的作用:
- 当Scheduler调用一个job,就会将jobExecutionContext对象传递给job的execute()方法的参数
- Job能够通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据
JobExecutionContext的方法:
- Scheduler getScheduler():获取当前调度器对象
- Trigger getTrigger():获取当前触发器对象
- JobDetail getJobDetail():获取任务实例对象
- Date getFireTime():当前任务的执行时间
- Date getNextFireTime():下一次任务的执行时间
- void put(Object var1, Object var2):使用给定的键将指定的值放入上下文的数据映射中
- Calendar getCalendar():获取触发的Calendar对象
- Object get(Object var1):从上下文的数据映射中获取具有给定键的值
- TriggerKey getRecoveringTriggerKey():返回最初计划的作业和现在正在恢复的作业
- JobDataMap getMergedJobDataMap():获取JobDataMap数据集合
- Job getJobInstance():获取为此执行创建的Job实例
- long getJobRunTime():job运行的时间
- ………………
例:
① job类
public class ExecutionJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取任务实例 JobDetail jobDetail = jobExecutionContext.getJobDetail(); System.out.println("任务类名:"+jobDetail.getJobClass().getSimpleName());//类名 System.out.println("任务组名:"+jobDetail.getKey().getGroup());//组名 System.out.println("任务名称:"+jobDetail.getKey().getName());//任务名 //获取触发器 Trigger trigger = jobExecutionContext.getTrigger(); //获取调度器 Scheduler scheduler = jobExecutionContext.getScheduler(); //获取时间 System.out.println("当前任执行时间:"+jobExecutionContext.getFireTime()); System.out.println("下一次任务执行时间:"+jobExecutionContext.getNextFireTime()); System.out.println("任务运行时间:"+jobExecutionContext.getJobRunTime()); //直接操作上下文数据映射的值 jobExecutionContext.put("qt","晴天"); System.out.println(jobExecutionContext.get("qt")); //获取JobDataMap JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap(); System.out.println(mergedJobDataMap.get("kxj")); } }
② 执行
//1,调度器(Scheduler),从工厂中获取调度实例 Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler(); //jobDataMap JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("kxj","空想家"); //2,任务实例(JobDetail) JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class)//加载任务类 .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称 .usingJobData(jobDataMap) .build(); //3,触发器(Trigger) SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1")//参数1:触发器名称 参数2:触发器组名称 .startNow()//启动后立即执行触发器 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))//每2秒执行重复执行一次 .build(); //Scheduler调度器关联任务实例和触发器,保证触发器定义的条件执行任务实例 defaultScheduler.scheduleJob(jobDetail,trigger); //启动调度器 defaultScheduler.start();
输出:
任务类名:ExecutionJob 任务组名:group1 任务名称:job1 当前任执行时间:Thu Oct 13 12:00:17 CST 2022 下一次任务执行时间:Thu Oct 13 12:00:19 CST 2022 任务运行时间:-1 晴天 空想家
4.3 JobDataMap说明
JobDataMap介绍:
- 在进行任务调度时,JobDataMap存储在JobExecutionContext中,非常方便获取
- JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象会被传递
- JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存储基本数据类型和引用数据类型
(1) 基本使用:
① 将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap,如下示例:
JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("kxj","空想家"); //2,任务实例(JobDetail) JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class)//加载任务类 .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称 .usingJobData(jobDataMap) //设置JobDataMap .build();
② 在job的执行过程中,可以从JobDataMap中取出数据,如下示例:
public class ExecutionJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取JobDataMap JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap(); System.out.println(mergedJobDataMap.get("kxj")); } }
private String kxj; public void setKxj(String kxj) { //在初始化时被自动注入JobDataMap在的值,key为属性名 this.kxj = kxj; } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取JobDataMap JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap(); System.out.println(mergedJobDataMap.get("kxj")==kxj); }
注:如果遇到同名的key,Trigger中的usingJobData会覆盖JobDetail中的usingJobData
4.4 Trigger触发器说明
Quartz有不同的触发器类型,其中用得最多的是SimpleTrigger和CronTrigger
Trigger的重要对象:
- jobKey:表示job实例的标识,触发器被触发时,该指定的job实例会被执行
- startTime:表示触发器第一次被触发时间,它的数据类型是java.util.Date
- endTime:指定触发器终止被触发的时间,它的数据类型是java.util.Date
例:
① 任务实现类
public class TriggerJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //当前时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd MM:mm:ss"); System.out.println("任务当前时间"+simpleDateFormat.format(date)); //获取Trigger Trigger trigger = jobExecutionContext.getTrigger(); //通过Trigger获取jobKey JobKey jobKey = trigger.getJobKey(); System.out.println(jobKey.getName());//获取job的名称 System.out.println(jobKey.getGroup());//获取job的组名 //任务开始时间 System.out.println("任务开始时间"+simpleDateFormat.format(trigger.getStartTime())); //任务结束时间 System.out.println("任务结束时间"+simpleDateFormat.format(trigger.getEndTime())); } }
② 调度
Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler(); JobDetail jobDetail = JobBuilder.newJob(TriggerJob.class) .withIdentity("job1", "group1") .build(); //任务开始时间 Date startdate = new Date(); startdate.setTime(startdate.getTime()+3000);//开始延迟3秒 //任务结束时间 Date enddate = new Date(); enddate.setTime(enddate.getTime()+5000);//结束延迟5秒 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startAt(startdate)//设置任务开始时间 .endAt(enddate)//设置任务结束时间 .build(); defaultScheduler.scheduleJob(jobDetail,trigger); defaultScheduler.start();
测试:
任务当前时间2022-10-13 10:14:57 job1 group1 任务开始时间2022-10-13 10:14:56 任务结束时间2022-10-13 10:14:58
4.4.1 SimpleTrigger触发器说明
SimpleTrigger对于设置和使用是最为简单的一种QuartzTrigger,它是为需要在特定的日期/时间启动,且以一个可能的间隔时间重复执行n次的jon所设计的
SimpleTrigger的几个重要方法:
- startAt():
- endAt():
- SimpleScheduleBuilder.withRepeatCount():指定执行次数
- SimpleScheduleBuilder.repeat****Forever():指定间隔时间
例1:在一个当前时间推迟3秒执行任务,任务每5秒中执行一次,总共执行3次
① 任务类
public class SimpleTriggerJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateformat = simpleDateFormat.format(date); System.out.println(dateformat+"--数据库备份!!"); } }
② SimpleTrigger
Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler(); JobDetail jobDetail = JobBuilder.newJob(SimpleTriggerJob.class) .withIdentity("job1", "group1") .build(); Date date = new Date(); date.setTime(date.getTime()+3000);//推迟三秒 SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startAt(date) .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(2))//5秒执行一次,总共3次(从0开始) .build(); defaultScheduler.scheduleJob(jobDetail,trigger); defaultScheduler.start();
输出:
2022-10-14 15:27:02--数据库备份!! 2022-10-14 15:27:07--数据库备份!! 2022-10-14 15:27:12--数据库备份!!
注:withRepeatCount()的值执行次数从0次开始,2代表着3次;如果不指定次数每个时间间隔会重复执行
例2:指定任务结束时间
Date enddate = new Date(); enddate.setTime(enddate.getTime()+10000);//当前时间推迟10秒 SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow()//启动会立即执行任务 .endAt(enddate)//任务结束时间 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(2))//5秒执行一次,总共3次(从0开始) .build();
注:
- SimpleTrigger的属性有:开始时间,结束时间,重复次数,重复时间间隔
- 重复次数的值可以为0,正整数,常量(SimpleTrigger.REPEAT_INDEFINTELY)
- 重复的时间间隔属性值必须为0或长整型的正整数,以毫秒做为时间单位,当重复的时间间隔为0时,意味着于Trigger同时触发执行
- 如果指定结束时间属性值,则结束时间优先于重复次数
4.4.2 CronTrigger触发器
简介:CronTriggers是基于日历的任务触发器,如果需要像日历那样按照日程触发任务,而不是像SimpleTrigger那样每隔特定的时间间隔来触发,CrinTrigger是很好的选择
使用CronTrigger,可以指定诸如“每个周五中午”,或者"每个工作日的9:30"或者“从每个同一、周三、周五的上午9: 00到上午10:00之间每隔五分钟"这样日程安排来触发。甚至,象SimpleTrigger一样,CronTrigger也有一个startTime以指定日程从什么时候开始,也有一个(可选的) endTime以指定何时日程不再继续
4.4.2.1 CronExpressions表达式
Cron表达式被用来配置CronTrigger实例,Cron表达式是一个由7个子表达式组成的字符串,每一个子表达式都描述了一个单独的日程细节,这些子表达式用空格隔开,分别表示:
- Seconds秒
- Minutes分钟
- Hours小时
- Day-of-Month月中的天
- Month月
- Day-of-Week周中的天
- Year 年(可选)
取值:
字段
|
是否必填
|
允许值
|
运行的特殊字符
|
Seconds(秒)
|
是
|
0-59
|
, - * /
|
Minutes(分钟)
|
是
|
0-59
|
, - * /
|
Hours(小时)
|
是
|
0-23
|
, - * /
|
Day-of-Month(天)
|
是
|
1-31
|
, - * / ? L W C
|
Month(月)
|
是
|
1-12或者JAN-DEC
|
, - * /
|
Day-of-Week(星期几)
|
是
|
1-7或者SUN-SAT
|
, - * / ? L C #
|
Year(年)
|
否
|
1970-2099
|
, - * /
|
特殊字符含义:
特殊字符
|
含义
|
*
|
表示域中每一个可能的值。因此在"Month"域中*表示每个月,"Day-of-Week"域中表示每个星期
|
?
|
表示指定值,使用的场景为不需要关心当前设置这个字段的值。因为"月份中的日期"和"星期中的日期"是互斥的,因此应该通过一个问号(?)来表明不想设置的字段
|
-
|
表示一个区间,例如:在小时字段上设置10-12,则表示10,11,12点都会触发
|
,
|
表示指定多个值,例如:在周字段上设置"1,2,3",表示周一、周二、周三都会触发
|
/
|
表示值的增量,例如:分钟域值为"0/15"它表示"每隔15分钟,从0开始"
|
L
|
可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个域中的意义不同。例如,在day-of-month域中的"L"表示这个月的最后一天,即,一月的31日,非闻年的二月的28日。如果它用在day-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week域中,这个字符跟在别的值后面,则表示"当月的最后的周XXX"。例如: "6L”或者"FRIL"都表示本月的最后一个周五。当使用"L"选项时,最重要的是不要指定列表或者值范围,否则会导致混乱
|
W
|
用来指定距离给定日最接近的周几(在day-of-week域中指定),例如:如果你为day-of-month域指定为"15W",则表示“距离月中15号最近的周几”
|
#
|
表示月中的第几个周几。例如: day-of-week域中的"6#3"或者"FRI#3"表示“月中第三个周五”
|
"0 0 10,15 * * ?" 每天上午10点,下午3点 "0 0/30 9-17 * * ?" 9点到17点每半,从0分开始每隔30分钟发送一次 "0 0 12 ? * WED" 表示每个星期三中午12点 "0 0 12 * * ?" 每天中午12点触发 "0 30 10 * * ?" 每天上午10:30触发 "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 "0 15 10 L * ?" 每月的最后一日的上午10:15触发
4.4.2.2 CronTrigger的使用
- CronScheduleBuilder.cronSchedule:指定Cron表达式
例:
CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * 14 10 ?"))//10月14号每5秒执行 .build();
4.4.2.3 Cron表达式生成工具
4.5 Scheduler调度器说明
Quartz以模块方式架构,Scheduler就是相当于直接连接器,把Trigger和Job很好的连接起来
Quartz的三个核心概念:调度器(Scheduler),任务(Job),触发器(Trigger)
Trigger对于job而言就好比一个驱动器,没有触发器来定时驱动作业,作业就无法运行;对于Job而言一个Job可以对应多个Trigger,但对于Trigger而言,一个Trigger只能对应一个Job,所以一个Trigger只能被指派一个Job,如果你需要一个更复杂的触发计划,可以创建多个Trigger并指派它们给同一个Job
Scheduler的创建方式:
(1) StdSchedulerFactory
Quartz默认的SchedulerFactory
- 使用一组(java.util.Properties)来创建和初始化Quartz调度器
- 配置参数一般存储在quartz.properties文件中
- 调用getScheduler方法就能创建和初始化调度器对象
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler();
用法一:输出调度器开始的时间
- Date schedulerJob(JobDetail jobDetail, Trigger trigger):返回日期
Date date = defaultScheduler.scheduleJob(jobDetail, trigger); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("调度器开始的时间:"+simpleDateFormat.format(date));
用法二:启动任务调度
- void start()
defaultScheduler.scheduleJob(jobDetail, trigger); defaultScheduler.start();
用法三:任务调度挂起,即暂停操作
- void standby()
defaultScheduler.scheduleJob(jobDetail, trigger); defaultScheduler.standby();
用法四:关闭任务调度
- shutdown(true):表示等待所以执行的job执行结束之后,再关闭Scheduler
- shutdown(true):表示直接关闭Scheduler
//Schenuler执行2秒后自动挂起 Thread.sleep(2000L); scheduler.standby(); //Schenuler执行5秒后自动开启 Thread.sleep(5000L); scheduler.start(); //Schenuler执行8秒后自动关闭 Thread.sleep(8000L); scheduler.shutdown(true)
5. Job的状态
job的状态:
- 无状态(默认):job每一次调用都会重新创建,JobDataMap也会被重新加载
- 有状态:job的多次调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap
默认job是无状态的,使用@PersistJobDataAfterExecution标注job类可以实现有状态
例1:使用无状态job尝试进行累加
public class CountJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDataMap mergedJobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); Integer number = (Integer) mergedJobDataMap.get("number"); number=number+1; System.out.println(number); jobExecutionContext.getJobDetail().getJobDataMap().put("number",number); } }
结果:
1 1 1 1
例2:使用有状态job尝试进行累加
@PersistJobDataAfterExecution public class CountJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDataMap mergedJobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); Integer number = (Integer) mergedJobDataMap.get("number"); number=number+1; System.out.println(number); jobExecutionContext.getJobDetail().getJobDataMap().put("number",number); }}
结果:
1 2 3 4
Comments | NOTHING
Warning: Undefined variable $return_smiles in /www/wwwroot/wql_luoqin_ltd/wp-content/themes/Sakura/functions.php on line 1109