在開發過程當中,須要實現定時來執行某些方法任務,這時可使用Quartz框架來實現這個功能。mysql
Quartz中主要包含幾個核心概念,以下:sql
- Job 表示一個工做,要執行的具體內容。此接口中只有一個方法,以下:
void execute(JobExecutionContext context)- JobDetail 表示一個具體的可執行的調度程序,Job 是這個可執行程調度程序所要執行的內容,另外 JobDetail 還包含了這個任務調度的方案和策略。
- Trigger 表明一個調度參數的配置,何時去調。
- Scheduler 表明一個調度容器,一個調度容器中能夠註冊多個 JobDetail 和 Trigger。當 Trigger 與 JobDetail 組合,就能夠被 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);
具體的工做類須要實現接口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."); } }
建立一個監聽類來實現配置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 }
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 }