zoukankan      html  css  js  c++  java
  • 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中存储的数据很可能是不确定的。

  • 相关阅读:
    前端资料
    贪心
    二叉树的最大深度
    最长回文子串
    动态规划-tsp
    动态规划
    spfa与SLF和LLL(复习)
    动态规划之最长 公共子序列和上升子序列
    最近最远距离之暴力优化
    基于Element-UI封装的季度插件
  • 原文地址:https://www.cnblogs.com/lzghyh/p/12343423.html
Copyright © 2011-2022 走看看