代码下载
https://gitee.com/cbeann/Demooo/tree/master/springboot-demo/src/main/java/com/example/scheduledemo
源码分析
引入@EnableScheduling注解做了什么?
我们打开@EnableScheduling注解源码后发现
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documented public @interface EnableScheduling { }
其实改注解同Import引入了一个类SchedulingConfiguration类,该类向IOC容器中注入了一个BeanPostProcessor:ScheduledAnnotationBeanPostProcessor
@Configuration @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(); } }
总结:@EnableScheduling 该类向IOC容器中注入了一个BeanPostProcessor:ScheduledAnnotationBeanPostProcessor
ScheduledAnnotationBeanPostProcessor初始化做了什么?
public ScheduledAnnotationBeanPostProcessor() { this.registrar = new ScheduledTaskRegistrar(); }
总结:就如代码所示,new一个ScheduledTaskRegistrar
TaskComponent(自定义类)生命周期中ScheduledAnnotationBeanPostProcessor做了什么?
下图是ScheduledAnnotationBeanPostProcessor.postProcessAfterInitialization方法的源码,第一个方框就是把带有Scheduled注解的方法找出来,第二个方框是对每一个方法执行processScheduled逻辑。
下面截取ScheduledAnnotationBeanPostProcessor.processScheduled方法里的部分代码,它会把方法放到ScheduledTaskRegistrar里(ScheduledAnnotationBeanPostProcessor无参构造方法new的对象)
什么时候开始启动定时任务呢?
我们先详细看一下ScheduledAnnotationBeanPostProcessor的实现的接口和类,其实它实现了ApplicationListener,其实ScheduledAnnotationBeanPostProcessor也是一个监听器。
public class ScheduledAnnotationBeanPostProcessor implements ScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware, SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean
那就有点门路了,最后肯定会调用ApplicationListener实现类(ScheduledAnnotationBeanPostProcessor)的某些方法,
最后其实跟下去,你就会发现他调用了ScheduledAnnotationBeanPostProcessor里
ScheduledTaskRegistrar的scheduleTasks方法
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)); } } }
然后就开始执行了
总结
思路
通过@EnableScheduling注解添加一个ScheduledAnnotationBeanPostProcessor,在Bean生命周期里拦截方法看是否有@Scheduled注解,如果有,把方法存到ScheduledAnnotationBeanPostProcessor里的ScheduledTaskRegistrar里。同时ScheduledAnnotationBeanPostProcessor又是linstener,最后ioc容器加载完毕后会通知linstener,然后就调用ScheduledAnnotationBeanPostProcessor里ScheduledTaskRegistrar的里存的方法去按照一定的逻辑去执行,就实现了以上逻辑。
总结
其实SpringBoot的自动装配原理也查不多,通过注解引入某个类(大多包含BeanPostProcessor),然后根据注解拦截Bean生命周期,把方法放在某个地方,然后最后通过监听器或者Runner去开启某个新功能。