Quartz框架來實現定時任務

  在開發過程當中,須要實現定時來執行某些方法任務,這時可使用Quartz框架來實現這個功能。mysql

一 Quartz簡單使用

  Quartz中主要包含幾個核心概念,以下:sql

  1. Job 表示一個工做,要執行的具體內容。此接口中只有一個方法,以下:
    void execute(JobExecutionContext context) 
  2. JobDetail 表示一個具體的可執行的調度程序,Job 是這個可執行程調度程序所要執行的內容,另外 JobDetail 還包含了這個任務調度的方案和策略。 
  3. Trigger 表明一個調度參數的配置,何時去調。 
  4. Scheduler 表明一個調度容器,一個調度容器中能夠註冊多個 JobDetail 和 Trigger。當 Trigger 與 JobDetail 組合,就能夠被 Scheduler 容器調度了。 

 1.1 配置Scheduler

  上文說Scheduler是一個調度容器,任意一個JobDetail和任意一個Trigger結合爲一對便可進行註冊,而Scheduler須要實例化,只有在實例化之後,才能執行他的啓動(start)、暫停(stand-by)、中止(shutdown)方法。app

注意:scheduler被中止後,除非從新實例化,不然不能從新啓動;只有當scheduler啓動後,即便處於暫停狀態也不行,trigger纔會被觸發(job纔會被執行)。框架

 1 SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
 2 
 3   Scheduler sched = schedFact.getScheduler();
 4 
 5   sched.start();
 6 
 7   // define the job and tie it to our HelloJob class
 8   JobDetail job = newJob(HelloJob.class)
 9       .withIdentity("myJob", "group1")
10       .build();
11 
12   // Trigger the job to run now, and then every 40 seconds
13   Trigger trigger = newTrigger()
14       .withIdentity("myTrigger", "group1")
15       .startNow()
16       .withSchedule(simpleSchedule()
17           .withIntervalInSeconds(40) //每40s執行一次
18           .repeatForever())
19       .build();
20 
21   // Tell quartz to schedule the job using our trigger
22   sched.scheduleJob(job, trigger);

1.2 實現jobDetail

  具體的工做類須要實現接口Job,接口須要實現一個execute方法,而具體的job要執行的任務,就寫在execute方法中。以下:  ide

public class HelloJob implements Job {

    public HelloJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      System.err.println("Hello!  HelloJob is executing.");
    }
  }

 

二 Quartz和Spring boot結合

  建立一個監聽類來實現配置Scheduler,使Spring boot在啓動時自動加載該類,開始定時任務。以下:函數

 1 @Component
 2 public class TimedRegister implements ApplicationListener<ApplicationReadyEvent> {
 3 
 4     @Autowired
 5     FindMessage findMessage;
 6 
 7     @Override
 8     public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
 9         try {
10             // Grab the Scheduler instance from the Factory
11             Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
12 
13             // and start it off
14             scheduler.start();
15 
16             // define the job and tie it to our HelloJob class
17             JobDetail mysqlDoJob = JobBuilder.newJob(MysqlTimedSendJob.class)
18                     .withIdentity("job1", "jobGroup1")
19                     .build();
20 
21             mysqlDoJob.getJobDataMap().put("findMessage", findMessage);
22 
23             Trigger mysqlTrigger = newTrigger()
24                     .withIdentity("trigger1", "triggerGroup1")
25                     .withSchedule(CronScheduleBuilder.cronSchedule("0 0 10 * * ?"))
26                     .build();
27 
28             scheduler.scheduleJob(mysqlDoJob, mysqlTrigger);
29 
30         } catch (Exception e) {
31             logger.error("TimedRegister daily job error", e);
32         }
33     }
34 }

  以上須要注意幾點:ui

  1. ApplicationListener接口中須要傳入監聽參數(ApplicationReadyEvent),由於若是不傳入參數的話,會對每一個event都進行監聽,則會發生同時執行好幾個定時任務這樣的慘狀。這個問題不僅存在與定時任務的監聽。spa

  2. 先看一段解釋:code

  咱們傳給scheduler一個JobDetail實例,由於咱們在建立JobDetail時,將要執行的job的類名傳給了JobDetail,因此scheduler就知道了要執行何種類型的job;每次當scheduler執行job時,在調用其execute(…)方法以前會建立該類的一個新的實例;執行完畢,對該實例的引用就被丟棄了,實例會被垃圾回收;這種執行策略帶來的一個後果是,job必須有一個無參的構造函數(當使用默認的JobFactory時);另外一個後果是,在job類中,不該該定義有狀態的數據屬性,由於在job的屢次執行中,這些屬性的值不會保留。那麼如何給job實例增長屬性或配置呢?如何在job的屢次執行中,跟蹤job的狀態呢?答案就是:JobDataMap,JobDetail對象的一部分。對象

  由於job的具體類不是Spring建立的,而是quartz建立的,因此不能經過注入的方式來調用findmessage,只能經過將這個findmessage建立對象後經過參數注入的方式由JobDataMap來傳入Job具體的實現中。因此咱們在jobdetail中添加參數。

mysqlDoJob.getJobDataMap().put("findMessage", findMessage);

  而後在job的具體方法中,經過getdetail而後getjobdatamap的方式來獲取具體的findMessage方法,從而實現定時執行一個方法的操做。

1 public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
2 
3         FindMessage findMessage = (FindMessage) jobExecutionContext.getJobDetail()
4                 .getJobDataMap().get("findMessage");
5         logger.info("get findMessage instance success");
6 
7         findMessage.findDayMessage();
8         logger.info("send ding from mysql is success");
9     }

 

三 Quartz中的JobDataMap使用指南

JobDataMap中能夠包含不限量的(序列化的)數據對象,在job實例執行的時候,可使用其中的數據;JobDataMap是Java Map接口的一個實現,額外增長了一些便於存取基本類型的數據的方法。

將job加入到scheduler以前,在構建JobDetail時,能夠將數據放入JobDataMap。

  因此能夠在添加JobDetail時添加jobDataMap,以下:

1 // define the job and tie it to our DumbJob class
2   JobDetail job = newJob(DumbJob.class)
3       .withIdentity("myJob", "group1") // name "myJob", group "group1"
4       .usingJobData("jobSays", "Hello World!")
5       .usingJobData("myFloatValue", 3.141f)
6       .build();

  而後在job的具體類中將其取出,以下:

 1 public class DumbJob implements Job {
 2 
 3     public DumbJob() {
 4     }
 5 
 6     public void execute(JobExecutionContext context)
 7       throws JobExecutionException
 8     {
 9       JobKey key = context.getJobDetail().getKey();
10 
11       JobDataMap dataMap = context.getJobDetail().getJobDataMap();
12 
13       String jobSays = dataMap.getString("jobSays");
14       float myFloatValue = dataMap.getFloat("myFloatValue");
15 
16       System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
17     }
18   }
相關文章
相關標籤/搜索