Spring Boot 中实现定时任务的两种方式!
第一种:使用注解@Scheduled
使用 @Scheduled 非常容易,直接创建一个 Spring Boot 项目,并且添加 web 依赖 spring-boot-starter-web
,项目创建成功后,添加 @EnableScheduling
注解,开启定时任务:
首先使用 @Scheduled 注解开启一个定时任务。
@SpringBootApplication @EnableScheduling public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
fixedRate 表示任务执行之间的时间间隔,具体是指两次任务的开始时间间隔,即第二次任务开始时,第一次任务可能还没结束。
@Scheduled(fixedRate=2000) public void fixedRate() { System.out.println("我是fixedRate:" + new Date()); }
fixedDelay 表示任务执行之间的时间间隔,具体是指本次任务结束到下次任务开始之间的时间间隔。
@Scheduled(fixedDelay =2000) public void fixedRate() { System.out.println("我是fixedDelay:" + new Date()); }
initialDelay 表示首次任务启动的延迟时间。
@Scheduled(initialDelay=2000) public void fixedRate() { System.out.println("我是initialDelay:" + new Date()); }
所有时间的单位都是毫秒。
@Scheduled 注解也支持 cron 表达式,使用 cron 表达式,可以非常丰富的描述定时任务的时间。cron 表达式格式如下:
[秒] [分] [小时] [日] [月] [周] [年]
推荐使用网站生成:http://cron.qqe2.com/
这一块需要大家注意的是,月份中的日期和星期可能会起冲突,因此在配置时这两个得有一个是 ?
通配符含义:
-
?
表示不指定值,即不关心某个字段的取值时使用。需要注意的是,月份中的日期和星期可能会起冲突,因此在配置时这两个得有一个是?
-
*
表示所有值,例如:在秒的字段上设置*
,表示每一秒都会触发 -
,
用来分开多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发 -
-
表示区间,例如在秒上设置 "10-12",表示 10,11,12秒都会触发 -
/
用于递增触发,如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50) -
#
序号(表示每月的第几个周几),例如在周字段上设置"6#3"表示在每月的第三个周六,(用 在母亲节和父亲节再合适不过了) -
周字段的设置,若使用英文字母是不区分大小写的 ,即 MON 与mon相同
-
L
表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会自动判断是否是润年), 在周字段上表示星期六,相当于"7"或"SAT"(注意周日算是第一天)。如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示"本月最后一个星期五" -
W
表示离指定日期的最近工作日(周一至周五),例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发,如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不允许区间"-") -
L
和W
可以一组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资 )
例如,在 @Scheduled 注解中来一个简单的 cron 表达式,每隔5秒触发一次,如下:
@Scheduled(cron ="0/5 * * * * *") public void fixedRate() { System.out.println("我是cron:" + new Date()); }
例如:
第一种:使用第三方框架 Quartz
开发基础:
1、定义你的job,如HollowJob,实现job接口,实现方法;
2、定义你的任务类,HollowJobScheduler
a.获取调度器Scheduler
b.定义你的任务实例
c.定义你的触发器
d.将任务期和触发器绑定
e.启动调度器
触发器:
Quartz有一些不同的触发器类型,不过,用得最多的是SimpleTrigger和CronTrigger。
(1)jobkey
表示job实例的标识,触发器被触发时,该指定的job实例会被执行。
(2)startTime
表示触发器的时间表,第一次开始被触发的时间,它的数据类型是java.util.Date。
(3)endTime
表示触发器终止被触发的时间,它的数据类型是java.util.Date。
Simple Trigger触发器
SimpleTrigger对于设置和使用是最为简单的一种QuartzTrigger。
它是为那种需要在特定的日期/时间启动,且以一个可能的间隔时间重复执行n次的Job所设计的。
例如:5秒执行一次
Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//触发器名,触发器分组 // .startNow()//现在就启动 .usingJobData("trigger1_data_key","trigger1_data_value")//将数据传入触发器的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message” .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5)//五秒启动一次,如果不写那么只执行一次 )
例如:执行6次后停止
Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//触发器名,触发器分组 // .startNow()//现在就启动 .usingJobData("trigger1_data_key","trigger1_data_value")//将数据传入触发器的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message” .withSchedule( SimpleScheduleBuilder.repeatSecondlyForever(5)//执行6次之后停止,默认要执行一次 )
需要注意的点
SimpleTrigger的属性有:开始时间、结束时间、重复次数和重复的时间间隔。
重复次数属性的值可以为0、正整数、或常量SimpleTrigger.REPEAT_INDEFINITELY。
重复的时间间隔属性值必须大于0或长整型的正整数,以毫秒作为时间单位,当重复的时间间隔为0时,意味着与Trigger同时触发执行。
如果有指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建一个每间隔10秒钟触发一次直到指定的结束时间的Trigger,而无需去计算从开始到结束的所重复的次数,我们只需
使用Cron表达式:
推荐一个表达式生成网址:http://cron.qqe2.com/
Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//触发器名,触发器分组 // .startNow()//现在就启动 .usingJobData("trigger1_data_key","trigger1_data_value")//将数据传入触发器的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message” .withSchedule( CronScheduleBuilder.cronSchedule("0/1 * * * * ? ")//执行6次之后停止,默认要执行一次 )
Scheduler的创建方式:
(1)StdSchdulerFactory
·使用一组参数(java.util.Properties)来创建和初始化Quarz调庭器
·配置参数一般存储在quartz.properties文件中
·调用getScheduler方法就能创建和初始化调度器对象
生成调度器的方式:
//1.调度器 Scheduler scheduler = new StdSchedulerFactory().getDefaultScheduler(); //2.调度器 StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler();
用法一:输出调度器开始的时间:
//4.将任务实例和触发器绑定,他的返回值就是调度器的开始时间 Date date = scheduler.scheduleJob(jobDetail, jobTrigger);
用法二:启动任务调度:
scheduler.start();
用法三:任务调度挂起,即暂停操作
scheduler.standby();
用法四:结束调度器
scheduler.shutdown();
shutdown(true)//表示等待所有正在执行的job执行完毕之后,在关闭Scheduler
shutdown(false)//表示直接关闭Scheduler
注意:如果任务结束了,不能通过start()来唤醒该任务,会提示错误
(2)DirectSchdulerFactory(了解)
DirectSchedulerFactory instance = DirectSchedulerFactory.getInstance();
Scheduler scheduler1 = instance.getScheduler();
quartz.properties属性解析(标红的都是项目中一般要使用的):
#设置默认调度程序的名称,如正在使用群集功能,则必须对群集中“逻辑上”相同的调度程序的每个实例使用相同的名称,重新赋值该值。 org.quartz.scheduler.instanceName = DefaultQuartzScheduler #如果您希望Quartz Scheduler通过RMI作为服务器导出本身,则为true。 org.quartz.scheduler.rmi.export = false #如果要连接(使用)远程服务的调度程序,则为true。还必须指定RMI注册表进程的主机和端口 - 通常是“localhost”端口1099 org.quartz.scheduler.rmi.proxy = false #org.quartz.scheduler.rmi.registryHost #org.quartz.scheduler.rmi.registryPort #设置这项为true使我们在调用job的execute()之前能够开始一个UserTransaction。 org.quartz.scheduler.wrapJobExecutionInUserTransaction = false #指定的线程池(这是quartz自带的实现类) org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool #线程数量(最好不要超过100,但是一定要 >0,创建0条线程是无意义的) org.quartz.threadPool.threadCount = 10 #优先级(最小是1,最大是10,默认是5) org.quartz.threadPool.threadPriority = 5 #自创建父线程 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true #作业最大延迟时间毫秒 org.quartz.jobStore.misfireThreshold = 60000 #数据保存方式为持久化 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
Quartz监听器
1.概念
Quartz的监听髓用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知。类似于任务执行过程中的邮件、短信类的提醒。Quarz监听器主要有JobListener、TriggerListener、SchedulerListener三种,顾名思义,分别表示任务、触发器、调度器对应的监听器。三者的使用方法类似,在开始介绍三种监听器之前,需要明确两个概念:全局监听器与非全局监听器,
二者的区别在于:
全局监听器能够接收到所有job/Trigger的事件通知,而非全局监听器只能接收到在其上注册job或Trigger的事件,不在其上注册job或Trigger则不会进行监听。
2.JobListener任务调度过程中,与任务Job相关的事件包括:job开始要执行的提示;job执行完成的提示灯
JobListener是一个已经存在的接口,我们可以对其重写
其中:
1)getName方法:用于获取该obListener的名称。
2)jobToBeExecuted方法:Scheduler在JobDeta将要被执行时调用这个方法。
3)jobExecutionVetoed方法:Scheduler在JobDeta即将被执行,但又被TriggerListerner否决时会调用该方法
4)jobWasExecuted方法:Scheduler在jobDeta被执行之后调用这个方法
定义一个监听器的实现MyJobListener:
//要实现默认的job监听器接头
public class MyJobListener implements JobListener { @Override public String getName() { System.out.println("我的名称是:"+this.getClass().getSimpleName()); return this.getClass().getSimpleName(); } @Override public void jobToBeExecuted(JobExecutionContext jobExecutionContext) { String name = jobExecutionContext.getJobDetail().getKey().getName(); System.out.println("job的名称是:"+name+" ;Scheduler在JobDeta将要被执行时调用这个方法。"); } @Override public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) { String name = jobExecutionContext.getJobDetail().getKey().getName(); System.out.println("job的名称是:"+name+" ;Scheduler在JobDeta即将被执行,但又被TriggerListerner否决时会调用该方法"); } @Override public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) { String name = jobExecutionContext.getJobDetail().getKey().getName(); System.out.println("job的名称是:"+name+" ;Scheduler在jobDeta被执行之后调用这个方法"); } }
定义你的任务
public class HollowJobSchedulerListener { public static void main(String[] args) throws SchedulerException { //1.调度器 // Scheduler scheduler = new StdSchedulerFactory().getDefaultScheduler(); StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler(); JobDetail jobDetail = JobBuilder.newJob(HollowJobListener.class) .withIdentity("job1", "job_grop1")//job名称,分组,没有指定组名,则默认是default .usingJobData("job1_data_key","job1_data_value")//将数据传入任务实例的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message”。 .build(); //3.触发器,由TriggerBuilder创建 Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//触发器名,触发器分组 // .startNow()//现在就启动 .usingJobData("trigger1_data_key","trigger1_data_value")//将数据传入触发器的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message” .startNow() .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5) ) .build(); //4.将任务实例和触发器绑定 scheduler.scheduleJob(jobDetail, jobTrigger); //创建并注册一个全局的监听器( EverythingMatcher任何地方,allJobs()所有的job) //scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());//代表任何地方的所有job //创建一个局部的监听器 scheduler.getListenerManager().addJobListener(new MyJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job2", "job_grop1")));//代表指定的job,通过jobkey判断,根据指定的job名称和job组找到指定job
//删除监听一样的套路
//scheduler.getListenerManager().removeJobListenerMatcher(new MyJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job1", "job_grop1")));
//scheduler.getListenerManager().removeJobListenerMatcher(new MyJobListener(),EverythingMatcher.allJobs());
//5.启动调度器 scheduler.start(); } }
TriggerListener监听器(使用方法同JobListener一样):
定义一个triggerlistener监听器的实现类MyTirggerListener:
1)getName方法:用于获取触发器的名称
2)triggerFired方法:当与监听器相关联的Trigger被触发,Job上的execute)方法将被执行时,Scheduler就调用该方法。
3)vetojobExecution方法:在Trigger 触发后,Job将要被执行时由 Scheduler 调用这个方法。TriggerListener给了一个选择去否决Job的执行。假如这个方法返回true,这个Job将不会为此次Trigger触发而得到执行。
4)triggerMisfired方法:Scheduler 调用这个方法是在Trigger 错过触发时。你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的Trigger时,长逻辑会导致骨牌效应。你应当保持这上方法尽量的小。
5)triggerComplete方法:Trigger被触发并且完成了Job的执行时,Scheduler调用这个方法。
public class MyTirggerListener implements TriggerListener { @Override public String getName() { String simpleName = this.getClass().getSimpleName(); System.out.println("触发器名称:"+simpleName); return simpleName; } @Override public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) { String name = trigger.getKey().getName(); System.out.println("触发器的名称是:"+name+"被触发"); } @Override public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) { //可以理解为将要触发执行的job的时候,这里加了一层限制,返回true,不执行,返回false执行job String name = trigger.getKey().getName(); System.out.println("触发器名称:"+name+"该job没有被触发"); return true;//返回true,这个Job将不会为此次Trigger触发而得到执行。
//return false;//返回false,这个JOb会执行
} @Override public void triggerMisfired(Trigger trigger) { String name = trigger.getKey().getName(); System.out.println("触发器名称:"+name+"没有触发"); } @Override public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) { String name = trigger.getKey().getName(); System.out.println("触发器名称:"+name+"Trigger被触发并且完成Job的执行了"); } }
定义你的任务:
public class HollowJobSchedulerTriggerListener { public static void main(String[] args) throws SchedulerException { //1.调度器 // Scheduler scheduler = new StdSchedulerFactory().getDefaultScheduler(); StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler(); JobDetail jobDetail = JobBuilder.newJob(HollowJobListener.class) .withIdentity("job1", "job_grop1")//job名称,分组,没有指定组名,则默认是default .usingJobData("job1_data_key","job1_data_value")//将数据传入任务实例的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message”。 .build(); //3.触发器,由TriggerBuilder创建 Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//触发器名,触发器分组 // .startNow()//现在就启动 .usingJobData("trigger1_data_key","trigger1_data_value")//将数据传入触发器的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message” .startNow() .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5) ) .build(); //4.将任务实例和触发器绑定 scheduler.scheduleJob(jobDetail, jobTrigger); //创建并注册一个全局的监听器( EverythingMatcher任何地方,allTrigger()所有的监听器) scheduler.getListenerManager().addTriggerListener(new MyTirggerListener(),EverythingMatcher.allTriggers());
//移除监听器
//scheduler.getListenerManager().removeTriggerListenerMatcher(new MyTirggerListener(),EverythingMatcher.allTriggers());
//scheduler.getListenerManager().removeTriggerListenerMatcher(new MyTirggerListener(),KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1_data_key","trigger1_data_value")));
//创建一个局部的监听器 //scheduler.getListenerManager().addTriggerListener(new MyTirggerListener(),KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1", "trigger_grop1")));//指定你的触发器的名称和分组 //5.启动调度器 scheduler.start(); } }
trigger监听的vetoJobExecution方法返回true时:
trigger监听的vetoJobExecution方法返回false时:
也可以通过构造器指定触发器的名称:
4.SchedulerListener
SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler发生严重错误,关闭scheduler等。
1)jobScheduled方法:用于部JobDetail时调用
2)jobunscheduled方法:用于卸载jobDetai时调用
3)triggerFinalized方法:当一个Trigger 来到了再也不会触发的状态时调用这个方法。除非这个Job已设置成了持久性,否则它就会从Scheduler 中移除。
4)triggerPaused(TriggerKey triggerKey)方法:Scheduler 调用这个方法是发生在一个Trigger或Trigger 组被暂停时。假如是Trigger组的话,triggerName参数将为null。
triggersPaused(String triggerGroup):触发器组"+triggerGroup+"正在被暂停时调用
5)triggersResumed方法:Scheduler 调用这个方法是发生成一个Trigger 或Trigger组从暂停中恢复时。假如是Trigger 组的话,假如是Trigger 组的话,triggerName参数将为nul。参数将为null。
6)jobsPaused方法:当一个或一组JobDetail 暂停时调用这个方法。
7)jobsResumed方法:当一个或一组Job从暂停上恢复时调用这个方法。假如是一个Job组,jobName参数将为null。
8)schedulerError方法:在Scheduler的正常运行期间产生一个严重错误时调用这个方法。
9)schedulerStarted方法:当Schedeler 开启时,调用该方法
10)schedulerinStandbyMode方法:当Scheduler处于StandBy模式时,调用该方法
11)schedulerShutdown方法:当Scheduler停止时,调用该方法
12)schedulingDataCleared方法:当Scheduler中的数据被清除时,调用该方法。
详情见下:
public class MySchedulerListener implements SchedulerListener { @Override public void jobScheduled(Trigger trigger) { String name = trigger.getKey().getName(); System.out.println("触发器名称是:"+name+",用于部JobDetail时调用"); } @Override public void jobUnscheduled(TriggerKey triggerKey) { String name = triggerKey.getName(); System.out.println("触发器名称是:"+name+",用于卸载jobDetai时调用"); } @Override public void triggerFinalized(Trigger trigger) { String name = trigger.getKey().getName(); //当一个Trigger 来到了再也不会触发的状态时调用这个方法。除非这个Job已设置成了持久性,否则它就会从Scheduler 中移除。 System.out.println("触发器名称是:"+name+",触发器被移除时时调用"); } @Override public void triggerPaused(TriggerKey triggerKey) { String name = triggerKey.getName(); //Trigger或Trigger 组被暂停时。假如是Trigger组的话,triggerName参数将为null。 System.out.println("触发器名称是:"+name+",Trigger或Trigger 组正在被暂停时调用"); } @Override public void triggersPaused(String triggerGroup) { System.out.println("触发器组"+triggerGroup+"正在被暂停时调用"); } @Override public void triggerResumed(TriggerKey triggerKey) { String name = triggerKey.getName(); System.out.println("触发器名称是:"+name+",正在从暂停中恢复时调用"); } @Override public void triggersResumed(String triggerGroup) { System.out.println("触发器组"+triggerGroup+"正在被恢复时调用"); } @Override public void jobAdded(JobDetail jobDetail) { System.out.println(jobDetail.getKey()+"添加工作任务!"); } @Override public void jobDeleted(JobKey jobKey) { System.out.println(jobKey+"删除工作任务!"); } @Override public void jobPaused(JobKey jobKey) { System.out.println(jobKey+"工作任务正在被暂停!"); } @Override public void jobsPaused(String s) { System.out.println("工作组"+s+"正在被暂停!"); } @Override public void jobResumed(JobKey jobKey) { System.out.println(jobKey.getName()+"正在被恢复!"); } @Override public void jobsResumed(String s) { System.out.println("工作组"+s+"正在被恢复!"); } @Override public void schedulerError(String s, SchedulerException e) { //在Scheduler的正常运行期间产生一个严重错误时调用这个方法。 System.out.println("产生一个严重错误时调用"+s+" "+e.getUnderlyingException()); } @Override public void schedulerInStandbyMode() { //当Scheduler处于StandBy模式时,调用该方法 System.out.println("当Scheduler处于StandBy模式时,调用该方法"); } @Override public void schedulerStarted() { System.out.println("当Schedeler 开启后,调用该方法"); } @Override public void schedulerStarting() { System.out.println("当Schedeler 开启时,调用该方法"); } @Override public void schedulerShutdown() { System.out.println("当Scheduler停止后,调用该方法"); } @Override public void schedulerShuttingdown() { System.out.println("当Schedeler 停止时,调用该方法"); } @Override public void schedulingDataCleared() { //当Scheduler中的数据被清除时,调用该方法。 System.out.println("当Scheduler中的数据被清除时,调用该方法。"); } }
定义你的任务:
public class HollowJobSchedulerTriggerListener { public static void main(String[] args) throws SchedulerException, InterruptedException { //1.调度器 StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler(); JobDetail jobDetail = JobBuilder.newJob(HollowJobListener.class) .withIdentity("job1", "job_grop1")//job名称,分组,没有指定组名,则默认是default .usingJobData("job1_data_key","job1_data_value")//将数据传入任务实例的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message”。 .build(); //3.触发器,由TriggerBuilder创建 Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//触发器名,触发器分组 // .startNow()//现在就启动 .usingJobData("trigger1_data_key","trigger1_data_value")//将数据传入触发器的map中,这里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple触发器”)会覆盖JobDetail中的.usinglobDataf"message” .startNow() .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(3) ) .build(); //4.将任务实例和触发器绑定 scheduler.scheduleJob(jobDetail, jobTrigger); //创建并注册一个全局的监听器( EverythingMatcher任何地方,allTrigger()所有的监听器) MySchedulerListener mySchedulerListener = new MySchedulerListener(); scheduler.getListenerManager().addSchedulerListener(mySchedulerListener); //删除一个监听器 // scheduler.getListenerManager().removeSchedulerListener(mySchedulerListener); //5.启动调度器 scheduler.start(); Thread.sleep(7000L);
//停止 scheduler.standby(); Thread.sleep(7000L); //清理数据
scheduler.clear(); Thread.sleep(7000L); //关闭调度器 scheduler.shutdown(); } }
小点:
@PersistJobDataAfterExecution //多次调用Job的时候,会对]ob进行持久化,即保存一个数据的信息(不会因为每一次都创建一个新的示例导致数据记录被清空)例如:jobdetailmap
如果你使用了@PersistJobDataAfterExecution注解,我们强烈建议你同时使用@DisallowConcurrentExecution注解,因为当同一个job(JobDetail)的两个实例被并发执行时,由于竞争,JobDataMap中存储的数据很可能是不确定的。