Quartz框架来实现定时任务

mac2022-06-30  93

  在开发过程中,需要实现定时来执行某些方法任务,这时可以使用Quartz框架来实现这个功能。

一 Quartz简单使用

  Quartz中主要包含几个核心概念,如下:

Job 表示一个工作,要执行的具体内容。此接口中只有一个方法,如下: void execute(JobExecutionContext context) JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。 Trigger 代表一个调度参数的配置,什么时候去调。 Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。 

 1.1 配置Scheduler

  上文说Scheduler是一个调度容器,任意一个JobDetail和任意一个Trigger结合为一对即可进行注册,而Scheduler需要实例化,只有在实例化以后,才能执行他的启动(start)、暂停(stand-by)、停止(shutdown)方法。

注意: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方法中。如下:  

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 }

  以上需要注意几点:

  1. ApplicationListener接口中需要传入监听参数(ApplicationReadyEvent),因为如果不传入参数的话,会对每个event都进行监听,则会发生同时执行好几个定时任务这样的惨状。这个问题不只存在与定时任务的监听。

  2. 先看一段解释:

  我们传给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 }

 

转载于:https://www.cnblogs.com/Mask-D/p/11215074.html

相关资源:Spring 框架自带定时任务和Quartz定时任务
最新回复(0)