通过前文我们基本梳理了定时任务体系:Timer和ScheduledExecutorService是JDK内置的定时任务方案,以及Netty内部基于时间轮实现的HashedWheelTimer,再到Quartz以及分布式任务(ElasticJob,xxl-job等等)。对于Springboot简单应用,还可以采用Spring自带task方式,本文主要介绍Spring自带的Task的案例和其实现方式。
实现案例
Spring Task封装的比较好,使用非常简单。
@EnableScheduling+@Scheduled
- 通过@EnableScheduling启用定时任务,@Scheduled定义任务
@EnableScheduling @Configuration public class ScheduleDemo { /** * 每隔1分钟执行一次。 */ @Scheduled(fixedRate = 1000 * 60 * 1) public void runScheduleFixedRate() { log.info("runScheduleFixedRate: current DateTime, {}", LocalDateTime.now()); } /** * 每个整点小时执行一次。 */ @Scheduled(cron = "0 0 */1 * * ?") public void runScheduleCron() { log.info("runScheduleCron: current DateTime, {}", LocalDateTime.now()); } }
- @Scheduled所支持的参数 :
cron fixedDelay fixedDelayString fixedRate fixedRateString initialDelay initialDelayString zone
进一步理解
我们再通过一些问题来帮助你更深入理解Spring Task实现方式。@pdai
使用Spring Task要注意什么?
- 关于异常处理
建议自行处理异常
- 关于超时处理
在实际的开发中,这个问题经常会出现,比如执行一段时间后定时任务不再执行了; 这种情况会发生在,比如你调用一个第三方接口,没有设置调用超时,继而引发异常,这时候当前任务便阻塞了。
~~java思维导图获取路径~~
Spring Task的原理?
Spring Task的源码在这里:
@EnableScheduling注解
添加@EnableScheduling注解会自动注入SchedulingConfiguration
* @author Chris Beams * @author Juergen Hoeller * @since 3.1 * @see Scheduled * @see SchedulingConfiguration * @see SchedulingConfigurer * @see ScheduledTaskRegistrar * @see Trigger * @see ScheduledAnnotationBeanPostProcessor */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documented public @interface EnableScheduling { }
SchedulingConfiguration中初始化ScheduledAnnotationBeanPostProcessor
SchedulingConfiguration配置中自动初始化ScheduledAnnotationBeanPostProcessor
@Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class SchedulingConfiguration { @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() { return new ScheduledAnnotationBeanPostProcessor(); } }
Spring 容器中 Bean 的生命周期流程
ScheduledTaskRegistrar注册task
在ScheduledAnnotationBeanPostProcessor构造函数中初始化了ScheduledTaskRegistrar
/** * Create a default {@code ScheduledAnnotationBeanPostProcessor}. */ public ScheduledAnnotationBeanPostProcessor() { this.registrar = new ScheduledTaskRegistrar(); }
ScheduledTaskRegistrar最主要的是注册各种类型的task (这种方式在新的版本中已经废弃了)
protected void scheduleTasks() { if (this.taskScheduler == null) { this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor); } if (this.triggerTasks != null) { for (TriggerTask task : this.triggerTasks) { addScheduledTask(scheduleTriggerTask(task)); } } if (this.cronTasks != null) { for (CronTask task : this.cronTasks) { addScheduledTask(scheduleCronTask(task)); } } if (this.fixedRateTasks != null) { for (IntervalTask task : this.fixedRateTasks) { addScheduledTask(scheduleFixedRateTask(task)); } } if (this.fixedDelayTasks != null) { for (IntervalTask task : this.fixedDelayTasks) { addScheduledTask(scheduleFixedDelayTask(task)); } } }
注册哪些Task,怎么设计类的呢?