Quartz基础知识
作者:互联网
Quartz框架是一个开源的企业级的任务调度服务
QurartZ的应用场景:定时邮件、定时更新缓存、定时统计数据
Quartz官网:http://www.quartz-scheduler.org/
- QuartZ的三个核心概念
-
任务:Job
Job是一个接口,开发者实现接口来定义任务。
- Job接口只有一抽象个方法
void execute(JobExecutionContext context)
,参数JobExecutionContext
类提供了调度上下文的各种信息
//创建任务类 public class CustomJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("当前日期时间:"+ LocalDateTime.now()); JobDetail jobDetail = jobExecutionContext.getJobDetail(); System.out.println(jobDetail.getKey().getGroup()); System.out.println(jobDetail.getKey().getName()); } }
-
Job实例在quartz中的 生命周期:每次调度器在执行Job时,调用execute方法前会创建一个job实例,调用结束后释放实例,由jvm的垃圾回收机制回收
-
JobDetail:JobDetail是接口,实现该接口的实例用来存储job实例的状态信息,调度器是借助JobDetail实例来添加Job实例的。
JobDetail最重要的属性:name(任务名称)、group(任务分组)、jobkey(任务名称和任务分组的键值对)、jobClass(任务类的字节码对象)、JobDataMap
JobBuilder jobBuilder = JobBuilder.newJob(CustomJob.class); //如果不设置,则默认组名为DEFAULT,任务名也会自动生成 jobBuilder.withIdentity("job1", "group1");//设置job任务名称和任务分组名 JobDetail jobDetail = jobBuilder.build();
-
JobDataMap:JobDataMap实现了Map接口,JobDataMap在任务调度时,调度任务上下文JobExecutionContext对象会获取jobdetail和trigger对象中各自存储的JobDataMap对象
//(1)JobDetail实例的时候可以设置jobdata,最终会保存到JobDataMap对象中 JobBuilder jobBuilder = JobBuilder.newJob(CustomJob.class); jobBuilder.withIdentity("job1", "group1") .usingJobData("jobDetailMsg", "任务数据"); //(2)触发器实例的时候也可以设置jobdata,最终会保存到JobDataMap对象中 TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger(); triggerBuilder.usingJobData("triggerMsg", "trigger消息"); //(3)Job接口的实现类(任务类)中可以获取上面(1)、(2)中设置的jobdetail public class CustomJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { /*通过任务执行时上下文对象jobExecutionContext获取到JobDataMap对象, 此JobDataMap对象包括了JobDetail和Trigger中设置的jobdata,此方法将二者进行了合并*/ JobDataMap map = jobExecutionContext.getMergedJobDataMap(); String triggerMsg1 = map.getString("triggerMsg"); String jobDetailMsg1 = map.getString("jobDetailMsg"); //只能获取Trigger对象中存储的jobdata String triggerMsg =(String) jobExecutionContext.getTrigger().getJobDataMap().getString("triggerMsg"); //只能获取jobDetail对象中存储的jobdata String jobDetailMsg = (String)jobExecutionContext.getJobDetail().getJobDataMap().getString("jobDetailMsg"); System.out.println(triggerMsg); System.out.println(jobDetailMsg); } }
-
JobKey:任务名称和任务分组的键值对
//设置任务名称和任务分组 JobBuilder jobBuilder = JobBuilder.newJob(CustomJob.class); jobBuilder.withIdentity("job1", "group1"); //获取任务名称和任务分组 Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取任务分组和任务名称 System.out.println("当前日期时间:"+ LocalDateTime.now()); JobDetail jobDetail = jobExecutionContext.getJobDetail(); System.out.println(jobDetail.getKey().getGroup()); System.out.println(jobDetail.getKey().getName()); //获取触发器名称和触发器分组 Trigger trigger = jobExecutionContext.getTrigger(); String triggername = trigger.getKey().getName(); String triggergroup = trigger.getKey().getGroup(); System.out.println(triggergroup+":"+triggername); }
-
Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化实例对象时会自动调用这些setter方法给job的属性赋值,值为JobDataMap中key对应的value
-
有状态的job和无状态的job
无状态job:每次job调用时,都会创建一个新的JobDataMap对象【默认是无状态job】
有状态job:多次job调用期间可以持有一些状态信息,这些信息存储在JobDataMap
//Job实现类上加注解@PersistJobDataAfterExecution就是有状态job,不加就是无状态job //加了注解@PersistJobDataAfterExecution后,Quartz会持久化jobdataMap进行持久化存储 @PersistJobDataAfterExecution public class CustomJob implements Job { private int count; public void setCount(int count) { this.count = count; } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDetail jobDetail = jobExecutionContext.getJobDetail(); jobDetail.getJobDataMap().put("count", count); } }
-
并发问题
Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞。
- 在Spring中这时需要设置concurrent的值为false, 禁止并发执行。
<property name="concurrent" value="true" />
- 当不使用spring的时候就需要在Job的实现类上加@DisallowConcurrentExecution的注释
@DisallowConcurrentExecution 禁止并发执行多个相同定义的JobDetail, 这个注解是加在Job类上的, 但意思并不是不能同时执行多个Job, 而是不能并发执行同一个Job Definition(由JobDetail定义), 但是可以同时执行多个不同的JobDetail, 举例说明,我们有一个Job类,叫做SayHelloJob, 并在这个Job上加了这个注解, 然后在这个Job上定义了很多个JobDetail, 如sayHelloToJoeJobDetail, sayHelloToMikeJobDetail, 那么当scheduler启动时, 不会并发执行多个sayHelloToJoeJobDetail或者sayHelloToMikeJobDetail, 但可以同时执行sayHelloToJoeJobDetail跟sayHelloToMikeJobDetail - @PersistJobDataAfterExecution 同样, 也是加在Job上,表示当正常执行完Job后, JobDataMap中的数据应该被改动, 以被下一次调用时用。当使用@PersistJobDataAfterExecution 注解时, 为了避免并发时, 存储数据造成混乱, 强烈建议把@DisallowConcurrentExecution注解也加上
- Job接口只有一抽象个方法
-
触发器:Trigger
Trigger是个接口,实现该接口来定义触发任务执行的时间条件
Trigger常用的两个子接口:
SimpleTrigger
【简单触发器】 、CronTrigger【cron表达式触发器】-
SimpleTrigger:当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger最适合
-
CronTrigger:可以通过
Cron
表达式定义出各种复杂时间规则的调度方案,CronTrigger触发器通过Cron表达式来控制调度任务的时间规则,Cron表达式的详细规则自己百度
注意:百度【在线Cron表达式生成器】可以自动生成Cron表达式
-
SimpleTrigger和CronTrigger两种的区别
SimpleTrigger触发器可以设置:开始时间、结束时间、重复次数和重复时间间隔
CronTrigger触发器是基于日历的调度器,时间间隔可以不规律
public class CronTriggerDemo { public static void main(String[] args) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(CustomJob.class) .usingJobData("jobDetailMsg", "jobDetailMsg") .withIdentity("任务1", "任务组A") .build(); CronTrigger cronTrigger = TriggerBuilder.newTrigger() .usingJobData("triggerMsg", "TriggerBuilder") .withIdentity("触发器1", "触发器分组A") .withSchedule(CronScheduleBuilder.cronSchedule("4/5 * * * * ? ")) .build(); //创建调度器 Scheduler scheduler = new StdSchedulerFactory().getDefaultScheduler(); scheduler.scheduleJob(jobDetail, cronTrigger); scheduler.start(); } } //任务类 public class CustomJob implements Job { private int count; public void setCount(int count) { this.count = count; } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取任务分组和任务名称 System.out.println("当前日期时间:"+ LocalDateTime.now()); JobDetail jobDetail = jobExecutionContext.getJobDetail(); System.out.println(jobDetail.getKey().getGroup()); System.out.println(jobDetail.getKey().getName()); //获取触发器名称和触发器分组 Trigger trigger = jobExecutionContext.getTrigger(); String triggername = trigger.getKey().getName(); String triggergroup = trigger.getKey().getGroup(); System.out.println(triggergroup+":"+triggername); /*通过任务执行时上下文对象jobExecutionContext获取到JobDataMap对象, 此JobDataMap对象包括了JobDetail和Trigger中设置的jobdata,此方法将二者进行了合并*/ JobDataMap map = jobExecutionContext.getMergedJobDataMap(); String triggerMsg1 = map.getString("triggerMsg"); String jobDetailMsg1 = map.getString("jobDetailMsg"); //只能获取Trigger对象中存储的jobdata String triggerMsg =(String) jobExecutionContext.getTrigger().getJobDataMap().getString("triggerMsg"); //只能获取jobDetail对象中存储的jobdata String jobDetailMsg = (String)jobExecutionContext.getJobDetail().getJobDataMap().getString("jobDetailMsg"); System.out.println(triggerMsg); System.out.println(jobDetailMsg); ++count; System.out.println(count); jobDe、tail.getJobDataMap().put("count", count); } }
-
-
调度器:Scheduler
- Scheduler是个接口,最常用的实现类StdSchedulerFactory
- Scheduler的实现类可以将任务和触发器关联起来,保证任务基于触发器设定的时间规则来执行
安排任务进执行计划的方法:Scheduler对象.schedulerJob(jobDetail,tirgger)
-
quartz的三种监听器:JobListener TriggerListener SchedulerListener【了解】
-
springboot中使用Quartz
/* spirng整合了Quartz框架,通过@EnableScheduling、 @Scheduled注解即可实现,记住是spring整合的,不是springboot整合的 */ @SpringBootApplication @EnableScheduling public class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class,args); } } @Service public class SchedulerService { @Scheduled(cron = "4/5 * * * * ? ") public void hello() { System.out.println(new Date()); } }
标签:Quartz,String,jobExecutionContext,基础知识,Job,JobDataMap,任务,println 来源: https://blog.csdn.net/user2025/article/details/89220975