实现定时任务,可以借助Quartz。SpringBoot开发的项目中,可以使用@Scheduled更简单的实现定时任务。
ScheduledAnnotationBeanPostProcessor继承BeanPostProcesso,在初始化bean后,通过“postProcessAfterInitialization”拦截到所有的用到“@Scheduled”注解的方法,并解析相应的的注解参数,放入“定时任务列表”等待后续处理;之后再“定时任务列表”中统一执行相应的定时任务(任务为顺序执行,先执行cron,之后再执行fixedRate)。
SpringBoot中使用@Scheduled启动定时任务,需要在启动类或者带@Configuration的配置类上加上@EnableScheduling注解。
原文链接:https://www.jianshu.com/p/92dfc36c2160/
一:前言本文主要介绍Spring Boot中使用定时任务的执行原理。
二:@Scheduled使用方式定时任务注解为@Scheduled。
使用方式举例如下:
//定义一个按时间执行的定时任务,在每天16:00执行一次。
@Scheduled(cron = "0 0 16 * * ?")
public void depositJob() { //执行代码}
//定义一个按一定频率执行的定时任务,每隔1分钟执行一次
@Scheduled(fixedRate = 1000 * 60)
public void job2() { //执行代码}
//定义一个按一定频率执行的定时任务,每隔1分钟执行一次,延迟1秒执行
@Scheduled(fixedRate = 1000 * 60,initialDelay = 1000)
public void updatePayRecords() { //执行代码}
备注:具体参数可以参考“spring-context-4.2.4.RELEASE.jar”下面的“org.springframework.scheduling.annotation.Scheduled"类。
三:@Scheduled代码执行原理说明简要介绍:
spring在初始化bean后,通过“postProcessAfterInitialization”拦截到所有的用到“@Scheduled”注解的方法,并解析相应的的注解参数,放入“定时任务列表”等待后续处理;之后再“定时任务列表”中统一执行相应的定时任务(任务为顺序执行,先执行cron,之后
执行fixedRate)。重要代码如下:第一步:依次加载所有的实现Scheduled注解的类方法。//说明:ScheduledAnnotationBeanPostProcessor继承BeanPostProcessor
@Overridepublic Object postProcessAfterInitialization(final Object bean, String beanName) { //省略多个判断条件代码 for (Map.Entry> entry : annotatedMethods.entrySet()) { Method method = entry.getKey(); for (Scheduled scheduled : entry.getValue()) { processScheduled(scheduled, method, bean); } } } return bean; }
第二步:将对应类型的定时器放入相应的“定时任务列表”中。
说明:ScheduledAnnotationBeanPostProcessor继承BeanPostProcessor。
获取scheduled类参数,之后根据参数类型、相应的延时时间、对应的时区放入不同的任务列表中
protected void processScheduled(Scheduled scheduled, Method method, Object bean) { //获取corn类型 String cron = scheduled.cron(); if (StringUtils.hasText(cron)) { Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers"); processedSchedule = true; String zone = scheduled.zone(); //放入cron任务列表中(不执行) this.registrar.addCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))); } //执行频率类型(long类型) long fixedRate = scheduled.fixedRate(); String fixedDelayString = scheduled.fixedDelayString(); if (fixedRate >= 0) { Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; //放入FixedRate任务列表中(不执行)(registrar为ScheduledTaskRegistrar) this.registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)); } //执行频率类型(字符串类型,不接收参数计算如:600*20) String fixedRateString = scheduled.fixedRateString(); if (StringUtils.hasText(fixedRateString){ Assert.isTrue(!processedSchedule, errorMessage); processedSchedule = true; if (this.embeddedValueResolver != null) { fixedRateString = this.embeddedValueResolver.resolveStringValue(fixedRateString); } fixedRate = Long.parseLong(fixedRateString); //放入FixedRate任务列表中(不执行) this.registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)); } } return bean;}
第三步:执行相应的定时任务。
定时任务先执行corn,判断定时任务的执行时间,计算出相应的下次执行时间,放入线程中,到相应的时间后进行执行。之后执行按“频率”(fixedRate)执行的定时任务,直到所有任务执行结束。
protected void scheduleTasks() { //顺序执行相应的Cron if (this.cronTasks != null) { for (CronTask task : this.cronTasks) { this.scheduledFutures.add(this.taskScheduler.schedule(
task.getRunnable(), task.getTrigger()));
}
}