文档
Quartz分布式任务调度Quartz分布式任务高度框架详解。Quartz是开源且具有丰富特性的“任务调度库”,能够集成

Quartz分布式任务调度Quartz分布式任务高度框架详解。Quartz是开源且具有丰富特性的“任务调度库”,能够集成

一、quartz概念< /h1> 1 . 基本介绍< /h2> quartz是OpenSymphony开源组织在job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合,也可以单独使用。< /p> quartz是开源且具有丰富特性的“任务调度库”,能够集成于任何

一、quartz概念< /h1>

1 . 基本介绍< /h2>

quartz是OpenSymphony开源组织在job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合,也可以单独使用。< /p>

quartz是开源且具有丰富特性的“任务调度库”,能够集成于任何的Java应用,小到独立的应用,大至电子商业系统。quartz能够创建亦简单亦复杂的调度,以执行上十、上百,甚至上万的任务。任务job被定义为标准的Java组件,能够执行任何你想要实现的功能。quartz调度框架包含许多企业级的特性,如JTA事务、集群的支持 。< /p>

简而言之,quartz就是基于Java实现的任务调度框架,用于执行你想要执行的任何任务。< /p>

官方网址:www.quartz-scheduler.org/
官方文档:www.quartz-scheduler.org/documentati …
原码地址:github.com/quartz-sche …< /p>

2. quartz运行环境< /h2>

  • quartz可以运行嵌入在另一个独立式应用程序< /li>
  • quartz可以在应用程序服务器(或Servlet容器)内被实例化,并且参与事务< /li>
  • quartz可以作为一个独立的程序运行(其自己的Java虚拟机内),可以通过RMI使用< /li>
  • quartz可以被实例化,作为独立的项目集群(负载平衡和故障转移功能),用于作业的执行< /li>
    < /ul>

    3 . quartz核心概念< /h2>

    • 任务 job< /code>< /p>

      job< /code> 就是你想要实现的任务类,每一个 job< /code> 必须实现org.quartz.job< /code> 接口,且只需实现接口定义的 execute( )< /code> 方法。< /p>
      < /li>

    • 触发器 Trigger< /code>< /p>

      trigger 为你执行任务的触发器,比如你想每天定时3点发送一份统计邮件,Trigger 将会设置3点执行该任务 。
      Trigger 主要包含两种 SimplerTrigger 和 CronTrigger 两种。详见 7.9 与 7.10< /p>
      < /li>

    • 调度器 scheduler< /code>< /p>

      scheduler 为任务的调度器,它会将任务 job 及触发器 Trigger 整合起来,负责基于 Trigger 设定的时间来执行 job。< /p>
      < /li>
      < /ul>

      4 . quartz的体系结构< /h2>

      < /p>

      二、Quart的使用< /h1>

      1、引入quartz的jar包< /h2>

      创建一个 springboot(版本:2.2.4.RELEASE) 应用,直接引入依赖即可< /p>

      <dependency< /span>>< /span>

      <dependency< /span>>< /span>
      <groupid< /span>>< /span>org.quartz-scheduler</groupid< /span>>< /span>
      <artifactId< /span>>< /span>quartz</artifactId< /span>>< /span>
      </dependency< /span>>< /span>

      <dependency< /span>>< /span>
      <groupid< /span>>< /span>org.quartz-scheduler</groupid< /span>>< /span>
      <artifactId< /span>>< /span>quartz-jobs</artifactId< /span>>< /span>
      </dependency< /span>>< /span>
      </dependency< /span>>< /span>
      < /code>< /pre>

      2、入门案例< /h2>

      (1)创建Hellojob任务类< /p>


      public< /span> class< /span> Hellojob< /span> implement< /span> job< /span> {

      @override< /span>
      public< /span> void< /span> execute< /span>(jobExecutionContext arg0)< /span> throw< /span> jobExecutionException {

      ystem.out.println(new< /span> date< /span>( ));
      }
      }
      < /code>< /pre>

      ( 2)创建任务调度类HelloschedulerDemo< /p>

      public< /span> class< /span> HelloschedulerDemo< /span>  { 

      public< /span> static< /span> void< /span> main< /span>( string [ ] args )< /span> throw< /span> Exception {

      scheduler< /span> scheduler< /span> =< /span> Stdschedulerfactory.getDefaultscheduler( ) ;

      jobdetail< /span> jobdetail< /span> =< /span> jobBuilder.newjob( )
      .withIdentity(" job1 "< /span>," group1 "< /span>)
      .build( ) ;

      Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger ( )
      .withidentity (" trigger1 "< /span>," group1 "< /span>)
      .startNow ( )
      .withSchedule(SimpleScheduleBuilder.simpleSchedule( ).withIntervalInSeconds(2< /span>).repeatForever( ))
      .build( ) ;

      scheduler.schedulejob(jobdetail,trigger) ;

      scheduler.start( ) ;

      }

      }
      < /code>< /pre>

      3、job和jobdetail详解< /h2>

      • job< /code>:工作任务调度的接口,任务需要实现该接口。该接口中定义execute方法,类似JDK提供的TimeTask类的run方法。在里面编写任务执行的业务逻辑。< /li>
      • job实例在quartz中的生命周期:每次调度器执行job时,它在调用execute方法前会==创建一个新的 job 实例==,当调用完成后,关联的job对象实例会被释放,释放的实例会被垃圾回收机制回收。< /li>
      • jobdetail< /code>:jobdetail为job实例提供了许多设置属性,以及jobDataMap成员变量属性,它用来存储特定job实例的状态信息,调度器需要借助jobdetail对象来添加job实例。< /li>
      • jobdetail重要属性:name< /code>、group< /code>、jobclass< /code>、jobDataMap< /code>< /li>
        < /ul>

        jobdetail< /span> job< /span> =< /span> jobBuilder.newjob(Hellojob.class)
        .withIdentity(" job1 "< /span>," group1 "< /span>)
        .build( ) ;

        System.out.println("name:"< /span> +job.getKey( ).getname( ));
        System.out.println(" group : "< /span> + job.getkey( ).getgroup ( ) ) ;
        system.out.println ("jobclass:"< /span> +job.getjobclass( ).getname( ));
        < /code>< /pre>

        4、jobExecutionContext< /h2>

        • 当 scheduler 调用一个 job,就会将 jobExecutionContext 传递给 job 的 execute( ) 方法;< /li>
        • job 能通过 jobExecutionContext 对象访问到 quartz 运行时候的环境以及 job 本身的明细数据。< /li>
          < /ul>

          public< /span> class< /span> Hellojob< /span> implement< /span> job< /span>  {
          @override< /span>
          public< /span> void< /span> execute< /span>(jobExecutionContext jobExecutionContext)< /span> throw< /span> jobExecutionException {

          Trigger< /span> trigger< /span> =< /span> jobExecutionContext.getTrigger ( ) ;
          jobdetail< /span> jobdetail< /span> =< /span> jobExecutionContext.getjobdetail( );
          scheduler< /span> scheduler< /span> =< /span> jobExecutionContext.getscheduler( );

          trigger.getKey( ).getname( );
          trigger.getKey( ).getGroup( );

          jobExecutionContext.getScheduledFireTime( );
          jobExecutionContext.getFireTime( );
          jobExecutionContext.getPreviousFireTime( );
          jobExecutionContext.getNextFireTime( );

          System.out.println(new< /span> date< /span>( ));
          }
          }
          < /code>< /pre>

          5、jobDataMap介绍< /h2>

          ( 1)使用map获取< /h3>

          • 在进行任务调度时,jobDataMap< /code> 存储在 jobExecutionContext< /code> 中,非常方便获取。< /li>
          • jobDataMap< /code> 可以用来装载任何可序列化的数据对象,当 job 实例对象被执行时这些参数对象会传递给它。< /li>
          • jobDataMap< /code> 实现了 JDK 的 Map 接口,并且添加了非常方便的方法用来存取基本数据类型。< /li>
            < /ul>

            在定义Trigger< /code> 或者 jobdetail< /code> 时,将 jobDataMap< /code> 传入,然后job< /code> 中便可以获取到jobDataMap< /code> 中的参数< /p>

            public< /span> class< /span> Helloscheduler< /span>  {
            public< /span> static< /span> void< /span> main< /span>( string [ ] args )< /span> throw< /span> schedulerException {

            scheduler< /span> defaultscheduler< /span> =< /span> Stdschedulerfactory.getDefaultscheduler( ) ;

            jobDataMap< /span> jobDataMap2< /span> =< /span> new< /span> jobDataMap< /span>( ) ;
            jobDataMap2.put(" message "< /span>,"jobdetailMessage"< /span>) ;

            jobdetail< /span> jobdetail< /span> =< /span> jobBuilder.newjob(Hellojob.class)
            .withIdentity(" job1 "< /span>," jobGroup1 "< /span>)
            .usingjobData(jobDataMap2)
            .build( ) ;

            jobDataMap< /span> jobDataMap< /span> =< /span> new< /span> jobDataMap< /span>( ) ;
            jobDataMap.put(" message "< /span>,"TriggerMessage"< /span>) ;

            Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger ( )
            .withidentity (" trigger1 "< /span>," triggerGroup1 "< /span>)
            .startNow ( )
            .withSchedule(SimpleScheduleBuilder.simpleSchedule( ).withIntervalInSeconds(2< /span>) .repeatForever ( ) )
            .endAt (new< /span> date< /span>(new< /span> date< /span>( ).getTime( ) + 3000L< /span>))
            .usingjobData(jobDataMap)
            .build( ) ;

            defaultscheduler.schedulejob(jobdetail,trigger);
            defaultscheduler.start( ) ;
            }
            }
            < /code>< /pre>

            Hellojob.java< /p>

            public< /span> class< /span> Hellojob< /span> implement< /span> job< /span>  {
            @override< /span>
            public< /span> void< /span> execute< /span>(jobExecutionContext jobExecutionContext)< /span> throw< /span> jobExecutionException {
            System.out.println(jobExecutionContext.getTrigger( ).getjobDataMap( ).get(" message "< /span>) ) ;
            system.out.println (jobExecutionContext.getjobdetail( ).getjobDataMap( ).get(" message "< /span>));

            System.out.println(jobExecutionContext.getMergedjobDataMap( ).get(" message "< /span>) ) ;
            system.out.println (new< /span> date< /span>( ));
            }
            }
            < /code>< /pre>

            ( 2)使用 Setter 方法获取< /h3>

            job实现类中添加setter方法对应jobDataMap的键值,quartz框架默认的jobFactory实现类在初始化job实例对象时会自动调用这些setter方法。< /p>

            Helloscheduler< /code> 类和上面一样。< /p>

            Hellojob.java:< /p>

            @Data< /span>
            public< /span> class< /span> Hellojob< /span> implement< /span> job< /span> {

            private< /span> string message;

            @override< /span>
            public< /span> void< /span> execute< /span>(jobExecutionContext jobExecutionContext)< /span> throw< /span> jobExecutionException {
            System.out.println(message);
            System.out.println(new< /span> date< /span>( ));
            }
            }
            < /code>< /pre>

            = = is 注意==:如果遇到同名的 注意==:如果遇到同名的key< /code>,Trigger< /code> 中 jobDataMap< /code> 的值会覆盖jobdetail< /code> 中 jobDataMap< /code> 同名的Key< /code>< /p>

            6、有状态的job和无状态的job(@PersistjobDataAfterExecution)< /h2>

            有状态的 job< /code> 可以理解为多次 job< /code> 调用期间可以持有一些状态信息,这些状态信息存储在jobDataMap< /code> 中,而默认的无状态job< /code> 每次调用时都会创建一个新的jobDataMap< /code>。< /p>

            (1)修改HelloschedulerDemo.java。在 jobdetail< /code> 中添加 .usingjobData(" count ",0)< /code>, 表示计数器 。< /p>

            jobdetail< /span> job< /span> =< /span> jobBuilder.newjob(Hellojob.class)
            .withIdentity(" job1 "< /span>," group1 "< /span>)
            .usingjobData(" message "< /span>,"打印日志"< /span>)
            .usingjobData(" count "< /span>,0< /span>)
            .build( ) ;
            < /code>< /pre>

            (2)Hellojob.java< /p>

            @Data< /span>
            @PersistjobDataAfterExecution< /span>
            public< /span> class< /span> Hellojob< /span> implement< /span> job< /span> {

            private< /span> Integer count ;

            @override< /span>
            public< /span> void< /span> execute< /span>(jobExecutionContext jobExecutionContext)< /span> throw< /span> jobExecutionException {
            System.out.println(++count);
            jobExecutionContext.getjobdetail( ).getjobDataMap( ).put(" count "< /span>,count);
            }
            }
            < /code>< /pre>

            Hellojob类没有添加 @PersistjobDataAfterExecution< /code> 注解,每次调用时都会创建一个新的 jobDataMap< /code>。不会累加。< /p>

            Hellojob类添加 @PersistjobDataAfterExecution< /code> 注解,多次调用期间可以持有一些状态信息,即可以实现 count< /code> 的累加。< /p>

            7、trigger< /h2>

            < /p>

            (1)SimpleTrigger触发器< /h3>

            SimpleTrigger< /code> 对于设置和使用是最为简单的一种quartzTrigger。< /p>

            它是为那种需要在特定的日期/时间启动,且以一个可能的间隔时间重复执行 n 次的 job 所设计的。< /p>

            案例一:表示在一个指定的时间段内,执行一次作业任务 ;< /p>

            SimpleTrigger 常用方法:< /p>

            方法< /th>

            说明< /th>< /tr>< /thead>

            startNow ( )< /td>

            scheduler 开始执行时,触发器也即执行< /td>< /tr>

            startAt(new date( ))< /td>

            在指定的时间开始执行< /td>< /tr>

            withintervalinseconds(2 )< /td>

            执行间隔,方法名中对应时间单位< /td>< /tr>

            repeatForever( )< /td>

            一直重复执行< /td>< /tr>

            withRepeatCount(3 )< /td>

            重复执行指定的次数< /td>< /tr>

            endAt(new date( ))< /td>

            结束时间< /td>< /tr>< /tbody>< /table>

            例子:< /p>


            Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger ( )
            .withidentity (" trigger1 "< /span>," triggerGroup1 "< /span>)
            .startNow ( )
            .withSchedule(SimpleScheduleBuilder.simpleSchedule( ).withIntervalInSeconds(2< /span>) .withRepeatCount (3< /span>))
            .endAt(new< /span> date< /span>(new< /span> date< /span>( ).getTime( ) + 3000L< /span>))
            .build( ) ;
            < /code>< /pre>

            需要注意的点< /p>

            • SimpleTrigger的属性有:开始时间、结束时间、重复次数和重复的时间间隔。< /li>
            • 重复次数属性的值可以为0、正整数、或常量 SimpleTrigger.REPEAT_INDEFINITELY。< /li>
            • 重复的时间间隔属性值必须为大于0或者长整形的正整数,以毫秒作为时间单位,当重复的时间间隔为0时,意味着与Trigger同时触发执行。< /li>
            • 如果有指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建一个每间隔10秒触发一次直到指定的结束时间的Trigger,而无需去计算从开始到结束的所重复的次数,我们只需简单的指定结束时间和使用REPEAT_INDEFINITELY作为重复次数的属性值即可。< /li>
              < /ul>
              < /blockquote>

              (2)CronTrigger触发器< /h3>

              如果你需要像日历那样按日程来触发任务,而不是像 SimpleTrigger< /code> 那样每隔特定的间隔时间触发,CronTrigger< /code> 通常比 SimpleTrigger< /code> 更有用,因为它是基于日历的作业调度器。< /p>

              案例:< /p>

              Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger( )
              .withIdentity(" trigger1 "< /span>," group1 "< /span>)
              .withSchedule(CronScheduleBuilder.cronSchedule ("0/5 * * * * ?"< /span>))
              .build( ) ;
              < /code>< /pre>

              8、 schedulerfactory< /h2>

              quartz以模块方式架构,因此,要使它运行,几个组件必须很好的咬合在一起。幸运的是,已经有了一些现存的助手可以完成这些工作。< /p>

              所有的scheduler实例由schedulerfactory创建。< /p>

              quartz的三个核心概念:调度器、任务、触发器,三者之间的关系是 :< /p>

              < /p>

              大家都知道,一个作业,比较重要的三个要素就是scheduler,jobdetail,Trigger;而Trigger对于job而言就好比一个驱动器,没有触发器来定时驱动作业,作业就无法运行;对于job而言,一个job可以对应多个Trigger,但对于Trigger而言,一个Trigger只能对应一个job,所以一个Trigger只能被指派给一个job;如果你需要一个更负责的触发计划,你可以创建多个Trigger并指派它们给同一个job。< /p>

              (1)Stdschedulerfactory< /h3>

              quartz< /code> 默认的 schedulerfactory< /code>< /p>

              • 使用一组参数 (java.util.property< /code>)来创建和初始化quartz调度器< /li>
              • 配置参数一般存储在quartz.propertie< /code> 文件中< /li>
              • 调用 getscheduler< /code>方法就能创建和初始化调度器对象< /li>
                < /ul>

                创建方法:< /p>


                scheduler< /span> defaultscheduler< /span> =< /span> Stdschedulerfactory.getDefaultscheduler( ) ;

                Stdschedulerfactory< /span> stdschedulerfactory< /span> =< /span> new< /span> Stdschedulerfactory< /span>( ) ;
                scheduler< /span> scheduler< /span> =< /span> stdschedulerfactory.getscheduler( ) ;
                < /code>< /pre>

                (2)Directschedulerfactory(了解)< /h3>

                Directschedulerfactory 是对 schedulerfactory 的直接实现,通过它可以直接构建 scheduler、ThreadPool 等< /p>

                Directschedulerfactory< /span> directschedulerfactory< /span> =< /span> Directschedulerfactory.getInstance( ) ;
                scheduler< /span> scheduler< /span> =< /span> directschedulerfactory.getscheduler( ) ;
                < /code>< /pre>

                9、scheduler 常用方法< /h2>

                scheduler.schedulejob(jobdetail,trigger);
                scheduler.checkExists(jobKey.jobKey(name,group))
                scheduler.checkExists(TriggerKey.triggerKey(name,group))
                scheduler.deletejob(jobKey.jobKey(name,group))

                scheduler.triggerjob(jobKey.jobKey(name,group),dataMap)

                scheduler.start( );
                scheduler.pausejob(jobKey);
                scheduler.standby( ) ;
                scheduler.shutdown ( ) ;
                scheduler.shutdown (true< /span>) ;
                scheduler.shutdown (false< /span>);
                < /code>< /pre>

                10、 quartz.propertie< /h2>

                默认路径:quartz-2.3.2< /code> 中的org.quartz.quartz.propertie< /code>< /p>

                我们也可以在项目的资源下添加quartz.propertie< /code> 文件,去覆盖底层的配置文件。< /p>

                org.quartz.scheduler.instanceName = quartzscheduler

                org.quartz.scheduler.instanceId = AUTO

                org.quartz.threadPool.threadCount = 5< /span>

                org.quartz.threadpool.threadpriority =5< /span>

                org.quartz.threadPool.class< /span> = org.quartz.simpl.SimpleThreadPool

                org.quartz.jobStore.class< /span> = org.quartz.simpl.RAMjobStore

                org.quartz.plugin.jobInitializer.class< /span> = org.quartz.plugins.xml.jobInitializationPlugin

                org.quartz.plugin.jobInitializer.overWriteExistingjobs = true
                org.quartz.plugin.jobInitializer.failOnFileNotFound = true
                org.quartz.plugin.jobInitializer.validating=false
                < /code>< /pre>

                也可以编写程序代码操作quartz.propertie文件的内容:< /p>


                Stdschedulerfactory< /span> schedulerfactory< /span> =< /span> new< /span> Stdschedulerfactory< /span>( ) ;

                property< /span> prop< /span> =< /span> new< /span> property< /span>( ) ;
                prop.put(Stdschedulerfactory.PROP_THREAD_POOL_CLASS," org.quartz.simpl . simplethreadpool "< /span>) ;
                prop.put ("org.quartz.threadPool.threadCount"< /span>,"5"< /span>);

                try< /span> {

                schedulerfactory.initialize(prop);

                scheduler< /span> scheduler< /span> =< /span> schedulerfactory.getscheduler( ) ;

                scheduler.start( ) ;
                } catch< /span> (schedulerException e) {
                e.printStackTrace( ) ;
                }
                < /code>< /pre>

                三、quartz监听器< /h1>

                1、概念< /h2>

                quartz的监听器用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知。类似于任务执行过程中的邮件、短信类的提醒。quartz监听器主要由jobListener、TriggerListener、schedulerListener三种,顾名思义,分布表示任务、触发器、调度器对应的监听器。三者的使用方法类似,在开始介绍三种监听器之前,需要明确两个概念:全局监听器与非全局监听器,二者的区别在于:< /p>

                • 全局监听器能够接收到所有的job/Trigger的事件通知< /li>
                • 而非全局监听器只能接收到在其上注册的job或者Trigger的事件,不在其上注册的job或Trigger则不会进行监听。< /li>
                  < /ul>

                  本课程关于全局与非全局的监听器的使用,将一一介绍。< /p>

                  2、jobListener< /h2>

                  任务调度过程中,与任务job相关的事件包括:job开始要执行的提示;job执行完成的提示等。< /p>

                  public< /span> interface< /span> jobListener< /span>  {
                  public< /span> string getname< /span>( )< /span>;
                  public< /span> void< /span> jobToBeExecuted< /span>(jobExecutionContext context)< /span>;
                  public< /span> void< /span> jobExecutionVetoed< /span>(jobExecutionContext context)< /span>;
                  public< /span> void< /span> jobwasexecute< /span>(jobExecutionContext context,jobExecutionException jobException)< /span>;
                  }
                  < /code>< /pre>

                  其中 :< /em>< /p>

                  . getname方法:用于获取该jobListener的名称。
                  . jobToBeExecuted方法:scheduler在jobdetail将要被执行时调用这个方法。
                  . jobExecutionVetoed方法:scheduler在jobdetail即将被执行,但又被TriggerListener否决时会调用该方法。
                  . jobwasexecute方法:scheduler在jobdetail被执行之后调用这个方法。< /p>

                  示例:< /p>

                  HellojobListener.java< /p>


                  public< /span> class< /span> HellojobListener< /span> implement< /span> job< /span> {

                  @override< /span>
                  public< /span> void< /span> execute< /span>(jobExecutionContext context)< /span> throw< /span> jobExecutionException {

                  date< /span> date< /span> =< /span> new< /span> date< /span>( ) ;
                  SimpledateFormat< /span> dateFormat< /span> =< /span> new< /span> SimpledateFormat< /span>(" yyyy - mm - dd hh : mm : ss "< /span>);
                  string< /span> datestring< /span> =< /span> dateFormat.format(date);

                  System.out.println(" 正在进行数据库的备份工作,备份数据库的时间是 : "< /span> +datestring);
                  }
                  }
                  < /code>< /pre>

                  创建自定义的jobListener< /p>

                  MyjobListener.java< /p>

                  public< /span> class< /span> MyjobListener< /span> implement< /span> jobListener< /span>  { 

                  @override< /span>
                  public< /span> string getname< /span>( )< /span> {
                  string< /span> name< /span> =< /span> this< /span>.getClass( ).getSimpleName( ) ;
                  System.out.println("监听器的名称是:"< /span> +name);
                  return< /span> name;
                  }

                  @override< /span>
                  public< /span> void< /span> jobToBeExecuted< /span>(jobExecutionContext context)< /span> {
                  string< /span> name< /span> =< /span> context.getjobdetail( ).getKey( ).getname( ) ;
                  System.out.println("job的名称是:"< /span> + name +" scheduler在jobdetail将要被执行时调用的方法"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobExecutionVetoed< /span>(jobExecutionContext context)< /span> {
                  string< /span> name< /span> =< /span> context.getjobdetail( ).getKey( ).getname( ) ;
                  System.out.println("job的名称是:"< /span> + name +" scheduler在jobdetail即将被执行,但又被TriggerListener否决时会调用该方法"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobwasexecute< /span>(jobExecutionContext context,jobExecutionException jobException)< /span> {
                  string< /span> name< /span> =< /span> context.getjobdetail( ).getKey( ).getname( ) ;
                  System.out.println("job的名称是:"< /span> + name +" scheduler在jobdetail被执行之后调用这个方法"< /span>);
                  }

                  }
                  < /code>< /pre>

                  执行调度器< /p>

                  HelloschedulerDemojobListener.java< /p>

                  public< /span> class< /span> HelloschedulerDemojobListener< /span>  { 

                  public< /span> static< /span> void< /span> main< /span>( string [ ] args )< /span> throw< /span> Exception {

                  scheduler< /span> scheduler< /span> =< /span> Stdschedulerfactory.getDefaultscheduler( ) ;

                  jobdetail< /span> jobdetail< /span> =< /span> jobBuilder.newjob(HellojobListener.class)
                  .withIdentity(" job1 "< /span>," group1 "< /span>)
                  .build( ) ;

                  Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger ( )
                  .withidentity (" trigger1 "< /span>," group1 "< /span>)
                  .startNow ( )
                  .withSchedule(SimpleScheduleBuilder.simpleSchedule( ).repeatSecondlyForever(5< /span>) .withRepeatCount (2< /span>))
                  .build( ) ;

                  scheduler.schedulejob(jobdetail,trigger);

                  scheduler.getListenerManager( ).addjobListener(new< /span> MyjobListener< /span>( ),KeyMatcher.keyEquals(jobKey.jobKey(" job1 "< /span>," group1 "< /span>))) ;

                  scheduler.start( ) ;

                  }

                  }
                  < /code>< /pre>

                  3、TriggerListener< /h2>

                  任务调度过程中,与触发器Trigger相关的事件包括:触发器触发、触发器未正确触发、触发器完成等 。< /p>

                  public< /span> interface< /span> TriggerListener< /span>  {
                  public< /span> string getname< /span>( )< /span>;
                  public< /span> void< /span> triggerFired< /span>(Trigger trigger,jobExecutionContext context)< /span>;
                  public< /span> boolean< /span> vetojobExecution< /span>(Trigger trigger,jobExecutionContext context)< /span>;
                  public< /span> void< /span> triggerMisfired< /span>( Trigger trigger )< /span>;
                  public< /span> void< /span> triggerComplete< /span>(Trigger trigger,jobExecutionContext context, CompletedExecutionInstruction triggerInstructionCode)< /span>
                  }
                  < /code>< /pre>

                  其中 :< /em>< /p>

                  . getname方法:用于获取触发器的名称。
                  . triggerFired方法:当与监听器关联的Trigger被触发,job上的Execute( )方法将被执行时,scheduler就调用该方法。
                  . vetojobExecution方法:在Trigger触发后,job将要执行时由scheduler调用这个方法。TriggerListener给了一个选择去否决job的执行。假如这个方法返回true,这个job将不会为此次Trigger触发而得到执行。
                  . triggerMisfired方法:scheduler调用这个方法是在Trigger错过触发时。你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的Trigger时,长逻辑会导致骨牌效应。你应当保持这个方法尽量的小。
                  . triggerComplete方法:Trigger被触发并且完成了job的执行时,scheduler调用这个方法。< /p>

                  示例:< /p>

                  下面的例子简单展示了TriggerListener的使用,其中创建并注册TriggerListener与jobListener几乎类似。< /p>

                  HellojobListener.java< /p>


                  public< /span> class< /span> HellojobListener< /span> implement< /span> job< /span> {

                  @override< /span>
                  public< /span> void< /span> execute< /span>(jobExecutionContext context)< /span> throw< /span> jobExecutionException {

                  date< /span> date< /span> =< /span> new< /span> date< /span>( ) ;
                  SimpledateFormat< /span> dateFormat< /span> =< /span> new< /span> SimpledateFormat< /span>(" yyyy - mm - dd hh : mm : ss "< /span>);
                  string< /span> datestring< /span> =< /span> dateFormat.format(date);

                  System.out.println(" 正在进行数据库的备份工作,备份数据库的时间是 : "< /span> +datestring);
                  }
                  }
                  < /code>< /pre>

                  MyTriggerListener.java< /p>

                  public< /span> class< /span> MyTriggerListener< /span> implement< /span> TriggerListener< /span>  { 

                  private< /span> string name;

                  public< /span> MyTriggerListener< /span>(string name)< /span> {
                  super< /span>( ) ;
                  this< /span>.name = name;
                  }
                  @override< /span>
                  public< /span> string getname< /span>( )< /span> {
                  return< /span> this< /span>.name;
                  }

                  @override< /span>
                  public< /span> void< /span> triggerFired< /span>(Trigger trigger,jobExecutionContext context)< /span> {
                  string< /span> name< /span> =< /span> this< /span>.getClass( ).getSimpleName( ) ;
                  System.out.println(name +"被触发"< /span>);
                  }

                  @override< /span>
                  public< /span> boolean< /span> vetojobExecution< /span>(Trigger trigger,jobExecutionContext context)< /span> {
                  string< /span> name< /span> =< /span> this< /span>.getClass( ).getSimpleName( ) ;

                  System.out.println(name +" 没有被触发"< /span>);
                  return< /span> false< /span>;
                  }

                  @override< /span>
                  public< /span> void< /span> triggerMisfired< /span>( Trigger trigger )< /span> {
                  string< /span> name< /span> =< /span> this< /span>.getClass( ).getSimpleName( ) ;

                  System.out.println(name +" 错过触发"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> triggerComplete< /span>(Trigger trigger,jobExecutionContext context,
                  CompletedExecutionInstruction triggerInstructionCode)< /span> {
                  string< /span> name< /span> =< /span> this< /span>.getClass( ).getSimpleName( ) ;

                  System.out.println(name +" 完成之后触发"< /span>);
                  }

                  }
                  < /code>< /pre>

                  HelloschedulerDemoTriggerListener.java< /p>

                  public< /span> class< /span> HelloschedulerDemoTriggerListener< /span>  { 

                  public< /span> static< /span> void< /span> main< /span>( string [ ] args )< /span> throw< /span> Exception {

                  scheduler< /span> scheduler< /span> =< /span> Stdschedulerfactory.getDefaultscheduler( ) ;

                  jobdetail< /span> jobdetail< /span> =< /span> jobBuilder.newjob(HellojobListener.class)
                  .withIdentity(" job1 "< /span>," group1 "< /span>)
                  .build( ) ;

                  Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger ( )
                  .withidentity (" trigger1 "< /span>," group1 "< /span>)
                  .startNow ( )
                  .withSchedule(SimpleScheduleBuilder.simpleSchedule( ).repeatSecondlyForever(5< /span>) .withRepeatCount (2< /span>))
                  .build( ) ;

                  scheduler.schedulejob(jobdetail,trigger) ;

                  scheduler.getListenerManager( ).addTriggerListener(new< /span> MyTriggerListener< /span>( ),KeyMatcher.keyEquals(TriggerKey.triggerKey(" trigger1 "< /span>," group1 "< /span>))) ;

                  scheduler.start( ) ;

                  }

                  }
                  < /code>< /pre>

                  4、schedulerListener< /h2>

                  schedulerListener会在scheduler的生命周期中关键事件发生时被调用。与scheduler有关的事件包括:增加一个job/Trigger,删除一个job/Trigger,scheduler发生严重错误,关闭scheduler等。< /p>

                  public< /span> interface< /span> schedulerListener< /span>  {
                  public< /span> void< /span> jobscheduled< /span>( Trigger trigger )< /span>;
                  public< /span> void< /span> jobUnscheduled< /span>( TriggerKey triggerKey )< /span>;
                  public< /span> void< /span> triggerFinalized< /span>( Trigger trigger )< /span>;
                  public< /span> void< /span> triggerspause< /span>(string triggerGroup)< /span>;
                  public< /span> void< /span> triggersResumed< /span>(string triggerGroup)< /span>;
                  public< /span> void< /span> jobspause< /span>(string jobGroup)< /span>;
                  public< /span> void< /span> jobsResumed< /span>(string jobGroup)< /span>;
                  public< /span> void< /span> schedulerError< /span>(string msg,schedulerException cause)< /span>;
                  public< /span> void< /span> schedulerStarted< /span>( )< /span>;
                  public< /span> void< /span> schedulerInStandbyMode< /span>( )< /span>;
                  public< /span> void< /span> schedulerShutdown< /span>( )< /span>;
                  public< /span> void< /span> schedulingdatacleare< /span>( )< /span>
                  }
                  < /code>< /pre>

                  其中 :< /em>< /p>

                  . jobscheduled方法:用于部署jobdetail时调用。
                  . jobUnscheduled方法:用于卸载jobdetail时调用。
                  . triggerFinalized方法:当一个Trigger来到了再也不会触发的状态时调用这个方法。除非这个job已设置成了持久性,否则它就会从scheduler中移除。
                  . triggerspause方法:scheduler调用这个方法是发生在一个Trigger或Trigger组被暂停时。假如是Trigger组的话,triggerName参数将为null。
                  . triggersResumed方法:scheduler调用这个方法是发生在一个Trigger或Trigger组从暂停中恢复时。假如是Trigger组的话,triggerName参数将为null。
                  . jobspause方法:当一个或一组jobdetail暂停时调用这个方法。
                  . jobsResumed方法:当一个或一组job从暂停上恢复时调用这个方法。假如是一个job组,jobName将为null。
                  . schedulerError方法:在scheduler的正常运行期间产生一个严重错误时调用这个方法。
                  . schedulerStarted方法:当scheduler开启时,调用该方法。
                  . schedulerInStandbyMode方法:当scheduler处于StandBy模式时,调用该方法。
                  . schedulerShutdown方法:当scheduler停止时,调用该方法。
                  . schedulingdatacleare方法:当scheduler中的数据被清除时,调用该方法。< /p>

                  示例:< /p>

                  下面的代码简单描述了如何使用schedulerListener方法:< /p>

                  HellojobListener.java< /p>


                  public< /span> class< /span> HellojobListener< /span> implement< /span> job< /span> {

                  @override< /span>
                  public< /span> void< /span> execute< /span>(jobExecutionContext context)< /span> throw< /span> jobExecutionException {

                  date< /span> date< /span> =< /span> new< /span> date< /span>( ) ;
                  SimpledateFormat< /span> dateFormat< /span> =< /span> new< /span> SimpledateFormat< /span>(" yyyy - mm - dd hh : mm : ss "< /span>);
                  string< /span> datestring< /span> =< /span> dateFormat.format(date);

                  System.out.println(" 正在进行数据库的备份工作,备份数据库的时间是 : "< /span> +datestring);
                  }
                  }
                  < /code>< /pre>

                  MyschedulerListener.java< /p>

                  public< /span> class< /span> MyschedulerListener< /span> implement< /span> schedulerListener< /span>  { 

                  @override< /span>
                  public< /span> void< /span> jobscheduled< /span>( Trigger trigger )< /span> {
                  string< /span> name< /span> =< /span> trigger.getKey( ).getname( ) ;

                  System.out.println(name +" 完成部署"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobUnscheduled< /span>( TriggerKey triggerKey )< /span> {
                  string< /span> name< /span> =< /span> triggerKey.getname( ) ;

                  System.out.println(name +" 完成卸载"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> triggerFinalized< /span>( Trigger trigger )< /span> {
                  string< /span> name< /span> =< /span> trigger.getKey( ).getname( ) ;

                  System.out.println(name +" 触发器被移除 "< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> triggerPaused< /span>( TriggerKey triggerKey )< /span> {
                  string< /span> name< /span> =< /span> triggerKey.getname( ) ;

                  System.out.println(name +" 正在被暂停"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> triggerspause< /span>(string triggerGroup)< /span> {

                  System.out.println("触发器组"< /span> +triggerGroup +" 正在被暂停"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> triggerresume< /span>( TriggerKey triggerKey )< /span> {

                  string< /span> name< /span> =< /span> triggerKey.getname( ) ;
                  System.out.println(name +" 正在从暂停中恢复 "< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> triggersResumed< /span>(string triggerGroup)< /span> {

                  System.out.println("触发器组"< /span> +triggerGroup +" 正在从暂停中恢复 "< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobadded< /span>(jobdetail jobdetail)< /span> {

                  System.out.println(jobdetail.getKey( ) +" 添加工作任务"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobdeleted< /span>(jobKey jobKey)< /span> {

                  System.out.println(jobKey +" 删除工作任务"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobPaused< /span>(jobKey jobKey)< /span> {

                  System.out.println(jobKey +" 工作任务正在被暂停 "< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobspause< /span>(string jobGroup)< /span> {

                  System.out.println("工作组"< /span> +jobGroup +" 正在被暂停"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobresumed< /span>(jobKey jobKey)< /span> {

                  System.out.println(jobKey +" 正在从暂停中恢复 "< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> jobsResumed< /span>(string jobGroup)< /span> {

                  System.out.println("工作组"< /span> +jobGroup +" 正在从暂停中恢复 "< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> schedulerError< /span>(string msg,schedulerException cause)< /span> {

                  System.out.println("产生严重错误的时候调用"< /span> +msg +" "< /span> +cause.getUnderlyingException( ));
                  }

                  @override< /span>
                  public< /span> void< /span> schedulerInStandbyMode< /span>( )< /span> {

                  System.out.println("调度器被挂起模式的时候调用"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> schedulerStarted< /span>( )< /span> {

                  System.out.println("调度器开启的时候调用"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> schedulerStarting< /span>( )< /span> {

                  System.out.println("调度器正在开启的时候调用"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> schedulerShutdown< /span>( )< /span> {

                  System.out.println(" 调度器关闭的时候调用 "< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> schedulerShuttingdown< /span>( )< /span> {

                  System.out.println("调度器正在关闭的时候调用"< /span>);
                  }

                  @override< /span>
                  public< /span> void< /span> schedulingdatacleare< /span>( )< /span> {

                  System.out.println(" 调度器数据被清除的时候调用 "< /span>);
                  }

                  }
                  < /code>< /pre>

                  HelloschedulerDemoTriggerListener.java< /p>

                  public< /span> class< /span> HelloschedulerDemoTriggerListener< /span>  { 

                  public< /span> static< /span> void< /span> main< /span>( string [ ] args )< /span> throw< /span> Exception {

                  scheduler< /span> scheduler< /span> =< /span> Stdschedulerfactory.getDefaultscheduler( ) ;

                  jobdetail< /span> jobdetail< /span> =< /span> jobBuilder.newjob(HellojobListener.class)
                  .withIdentity(" job1 "< /span>," group1 "< /span>)
                  .build( ) ;

                  Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger ( )
                  .withidentity (" trigger1 "< /span>," group1 "< /span>)
                  .startNow ( )
                  .withSchedule(SimpleScheduleBuilder.simpleSchedule( ).repeatSecondlyForever(5< /span>) .withRepeatCount (2< /span>))
                  .build( ) ;

                  scheduler.schedulejob(jobdetail,trigger) ;

                  scheduler.getListenerManager( ).addschedulerListener(new< /span> MyschedulerListener< /span>( ));

                  scheduler.start( ) ;

                  Thread.sleep(7000L< /span>) ;

                  scheduler.shutdown( ) ;
                  }

                  }
                  < /code>< /pre>

                  四、持久化到Mysql中< /h1>

                  1. 下载sql文件< /h2>

                  quartz 原码中有 sql 文件:< /p>

                  下载然后导入到数据库中,我这里使用的是 mysql5.7< /p>

                  表名< /th>

                  描述< /th>< /tr>< /thead>

                  QRTZ_BLOB_TRIGGERS< /td>

                  作为 Blob 类型存储(用于 quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,jobStore 并不知道如何存储实例的时候)< /td>< /tr>

                  QRTZ_CALENDARS< /td>

                  以 Blob 类型存储 quartz 的 Calendar 信息< /td>< /tr>

                  QRTZ_CRON_TRIGGERS< /td>

                  存储 Cron Trigger,包括 Cron 表达式和时区信息< /td>< /tr>

                  QRTZ_FIRED_TRIGGERS< /td>

                  存储与已触发的 Trigger 相关的状态信息,以及相联 job 的执行信息< /td>< /tr>

                  QRTZ_JOB_DETAILS< /td>

                  存储每一个已配置的 job 的详细信息< /td>< /tr>

                  qrtz_locks< /td>

                  存储程序的非观锁的信息(假如使用了悲观锁)< /td>< /tr>

                  qrtz_paused_trigger_grps< /td>

                  存储已暂停的 Trigger 组的信息< /td>< /tr>

                  QRTZ_SCHEDULER_STATE< /td>

                  存储少量的有关 scheduler 的状态信息,和别的 scheduler 实例(假如是用于一个集群中)< /td>< /tr>

                  QRTZ_SIMPLE_TRIGGERS< /td>

                  存储简单的 Trigger,包括重复次数,间隔,以及已触的次数< /td>< /tr>

                  QRTZ_SIMPROP_TRIGGERS< /td>

                  < /td>< /tr>

                  QRTZ_TRIGGERS< /td>

                  存储已配置的 Trigger 的信息< /td>< /tr>< /tbody>< /table>

                  2 . 引入依赖< /h2>

                  <parent< /span>>< /span>
                  <groupid< /span>>< /span>org.springframework.boot</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>spring-boot-starter-parent</artifactId< /span>>< /span>
                  <version< /span>>< /span>2.2.4.RELEASE</version< /span>>< /span>
                  <relativePath< /span>/>< /span>
                  </parent< /span>>< /span>
                  <groupid< /span>>< /span>com.zyx</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>quartz</artifactId< /span>>< /span>
                  <version< /span>>< /span>0.0.1-SNAPSHOT</version< /span>>< /span>

                  <properties< /span>>< /span>
                  <java.version< /span>>< /span>1.8</java.version< /span>>< /span>
                  </properties< /span>>< /span>
                  <dependency< /span>>< /span>
                  <dependency< /span>>< /span>
                  <groupid< /span>>< /span>org.springframework.boot</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>spring-boot-starter</artifactId< /span>>< /span>
                  </dependency< /span>>< /span>

                  <dependency< /span>>< /span>
                  <groupid< /span>>< /span>org.quartz-scheduler</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>quartz</artifactId< /span>>< /span>
                  <exclusion< /span>>< /span>
                  <exclusion< /span>>< /span>

                  <groupid< /span>>< /span>com.mchange</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>c3p0</artifactId< /span>>< /span>
                  </exclusion< /span>>< /span>
                  </exclusion< /span>>< /span>
                  </dependency< /span>>< /span>

                  <dependency< /span>>< /span>
                  <groupid< /span>>< /span>org.quartz-scheduler</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>quartz-jobs</artifactId< /span>>< /span>
                  </dependency< /span>>< /span>

                  <dependency< /span>>< /span>
                  <groupid< /span>>< /span>org.projectlombok</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>lombok</artifactId< /span>>< /span>
                  <optional< /span>>< /span>true</optional< /span>>< /span>
                  </dependency< /span>>< /span>

                  <dependency< /span>>< /span>
                  <groupid< /span>>< /span>org.springframework</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>spring-context-support</artifactId< /span>>< /span>
                  </dependency< /span>>< /span>

                  <dependency< /span>>< /span>
                  <groupid< /span>>< /span>mysql</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>mysql-connector-java</artifactId< /span>>< /span>
                  </dependency< /span>>< /span>

                  <dependency< /span>>< /span>
                  <groupid< /span>>< /span>org.springframework.boot</groupid< /span>>< /span>
                  <artifactId< /span>>< /span>spring - boot - starter - jdbc</artifactId< /span>>< /span>
                  </dependency< /span>>< /span>
                  </dependency< /span>>< /span>
                  < /code>< /pre>

                  3. 配置schedulerfactory< /h2>

                  配置数据源 :< /p>

                  spring:< /span>
                  datasource:< /span>
                  username:< /span> root< /span>
                  password:< /span> root< /span>
                  url :< /span> jdbc:mysql://10.211.55.12:3306/test< /span>
                  driver-class-name:< /span> com.mysql.cj.jdbc.Driver< /span>
                  < /code>< /pre>

                  配置 schedulerfactory:< /p>

                  @configuration< /span>
                  public< /span> class< /span> ScheduleConfig< /span> {

                  @Bean< /span>
                  public< /span> schedulerfactoryBean schedulerfactoryBean< /span>(DataSource dataSource)< /span>
                  {
                  schedulerfactoryBean< /span> factory< /span> =< /span> new< /span> schedulerfactoryBean< /span>( ) ;
                  factory.setDataSource(dataSource) ;

                  property< /span> prop< /span> =< /span> new< /span> property< /span>( ) ;
                  prop.put(" org.quartz.scheduler.instancename "< /span>,"Zyxscheduler"< /span>) ;
                  prop.put ("org.quartz.scheduler.instanceId"< /span>," auto "< /span>) ;

                  prop.put (" org.quartz.threadPool.class "< /span>," org.quartz.simpl . simplethreadpool "< /span>) ;
                  prop.put ("org.quartz.threadPool.threadCount"< /span>," 20 "< /span>) ;
                  prop.put (" org.quartz.threadpool.threadpriority "< /span>,"5"< /span>) ;

                  prop.put ("org.quartz.jobStore.class"< /span>,"org.quartz.impl.jdbcjobstore.jobStoreTX"< /span>) ;

                  prop.put ("org.quartz.jobStore.isClustered"< /span>,"true"< /span>) ;
                  prop.put ("org.quartz.jobStore.clusterCheckinInterval"< /span>,"15000"< /span>) ;
                  prop.put ("org.quartz.jobStore.maxMisfiresToHandleAtATime"< /span>,"1"< /span>) ;
                  prop.put ("org.quartz.jobStore.txIsolationLevelSerializable"< /span>,"true"< /span>) ;

                  prop.put(" org.quartz.jobstore.misfirethreshold "< /span>,"12000"< /span>) ;
                  prop.put (" org.quartz.jobStore.tablePrefix "< /span>,"QRTZ_"< /span>);
                  factory.setquartzproperty(prop) ;

                  factory.setschedulerName("Zyxscheduler"< /span>);

                  factory.setStartupDelay(1< /span>);
                  factory.setApplicationContextschedulerContextKey(" applicationcontextkey "< /span>);

                  factory.setOverwriteExistingjobs(true< /span>);

                  factory.setAutoStartup(true< /span>) ;

                  return< /span> factory;
                  }
                  }
                  < /code>< /pre>

                  4. 使用自定义的scheduler< /h2>

                  定义一个简单的 job:< /p>

                  @Data< /span>
                  public< /span> class< /span> Hellojob< /span> implement< /span> job< /span> {

                  @override< /span>
                  public< /span> void< /span> execute< /span>(jobExecutionContext jobExecutionContext)< /span> throw< /span> jobExecutionException {
                  System.out.println(new< /span> date< /span>( ));
                  }
                  }
                  < /code>< /pre>

                  使用自定义的 scheduler:< /p>

                  @SpringBootTest< /span>
                  class< /span> quartzApplicationTests< /span> {

                  @Autowired< /span>
                  private< /span> schedulerfactoryBean factoryBean;

                  @Test< /span>
                  void< /span> contextload< /span>( )< /span> throw< /span> schedulerException,InterruptedException {
                  scheduler< /span> scheduler< /span> =< /span> factoryBean.getscheduler( ) ;
                  scheduler.clear( ) ;

                  jobdetail< /span> jobdetail< /span> =< /span> jobBuilder.newjob(Hellojob.class)
                  .withIdentity(" job1 "< /span>," jobGroup1 "< /span>)
                  .build( ) ;

                  Trigger< /span> trigger< /span> =< /span> TriggerBuilder.newTrigger( )
                  .startNow ( )
                  .withIdentity(" trigger1 "< /span>," triggerGroup1 "< /span>)
                  .withSchedule(SimpleScheduleBuilder.simpleSchedule( ).withIntervalInSeconds(2< /span>).repeatForever( ))
                  .build( ) ;

                  scheduler.schedulejob(jobdetail,trigger);
                  scheduler.start( ) ;
                  Thread.sleep(100000< /span>);
                  }
                  }
                  < /code>< /pre>

                  5. 查看数据库< /h2>

                  查看数据库,可以发现 quartz 中相关的数据已经保存到数据库中了

                  < /p>

                  6. 再次启动 scheduler< /h2>

                  直接让程序运行起来,不创建新的定时任务,会发现刚才保存到数据库中的定时任务会自动执行< /p>

                  @SpringBootTest< /span>
                  class< /span> quartzApplicationTests< /span> {

                  @Autowired< /span>
                  private< /span> schedulerfactoryBean factoryBean;

                  @Test< /span>
                  void< /span> contextload< /span>( )< /span> throw< /span> schedulerException,InterruptedException {
                  Thread.sleep(100000< /span>);
                  }

                  }
                  < /code>< /pre>