springboot之定时任务


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中存储的数据很可能是不确定的。

打赏

免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2021 CODEPRJ.COM