在开发过程当中,须要实现定时来执行某些方法任务,这时可使用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 }