目录
- 1.ScheduledAnnotationBeanPostProcessor
 - 1.1 SmartInitializingSingleton#afterSingletonsInstantiated
 - 1.2 RefreshScope处理ContextRefreshedEvent创建refresh中的bean
 - 1.3 ScheduledAnnotationBeanPostProcessor本身也能处理ContextRefreshedEvent
 - 2.@RefreshScope的影响
 - 2.1 ThreadPoolTaskScheduler在哪里配置的?
 - 2.2 TestController改造成ApplicationListener<RefreshScopeRefreshedEvent>
 
1.ScheduledAnnotationBeanPostProcessor
@EnableScheduling
- @Import(SchedulingConfiguration.class)
 - 注册了ScheduledAnnotationBeanPostProcessor
 

@RestController
@RefreshScope  //动态感知修改后的值
public class TestController implements ApplicationListener<RefreshScopeRefreshedEvent>{
    @Value("${common.age}")
     String age;
    @Value("${common.name}")
     String name;
    @GetMapping("/common")
    public String hello() {
        return name+","+age;
    }
    //触发@RefreshScope执行逻辑会导致@Scheduled定时任务失效
    @Scheduled(cron = "*/3 * * * * ?")  //定时任务每隔3s执行一次
    public void execute() {
        System.out.println("定时任务正常执行。。。。。。");
    }
    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
        this.execute();
    }
}
1.1 SmartInitializingSingleton#afterSingletonsInstantiated
ScheduledAnnotationBeanPostProcessor#afterSingletonsInstantiated
- DefaultListableBeanFactory#preInstantiateSingletons
 - SmartInitializingSingleton#afterSingletonsInstantiated
 - 没干啥重要事情
 
1.2 RefreshScope处理ContextRefreshedEvent创建refresh中的bean
并调用ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization找出TestController中加了@Scheduled注解的方法。
ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization
- 发布ContextRefreshedEvent
 - RefreshScope#onApplicationEvent
 - Object bean = this.context.getBean(name); 获取scope为refresh的bean:scopedTarget.testController
 - 会调用至postProcessAfterInitialization
 - 找到有@Scheduled注解的方法execute()
 - tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
 
1.3 ScheduledAnnotationBeanPostProcessor本身也能处理ContextRefreshedEvent
这里真正开始调度1.2中找到的任务。
ScheduledAnnotationBeanPostProcessor#onApplicationEvent
- ScheduledAnnotationBeanPostProcessor也会处理ContextRefreshedEvent
 - ScheduledAnnotationBeanPostProcessor#finishRegistration
 - this.taskScheduler设置为ThreadPoolTaskScheduler(哪里配置的?)
 - ScheduledTaskRegistrar#afterPropertiesSet
 - ScheduledTaskRegistrar#scheduleTasks
 - 开始执行任务,这cronTasks不为空,则执行该任务
addScheduledTask(scheduleCronTask(task)); - ScheduledTaskRegistrar#scheduleCronTask
 - scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());
 - ThreadPoolTaskScheduler#schedule
 - ReschedulingRunnable#schedule以及ReschedulingRunnable#run实现定时调度,线程池为ScheduledThreadPoolExecutor
 
2.@RefreshScope的影响
当Nacos Config配置中心发布配置时,会调用RefreshScope#refreshAll。
此时会ScheduledAnnotationBeanPostProcessor#postProcessBeforeDestruction会将加了@RefreshScope的TestController里面的任务全部cancel掉。
    public void refreshAll() {
        super.destroy();
        this.context.publishEvent(new RefreshScopeRefreshedEvent());
    }
RefreshScope#refreshAll
- GenericScope.BeanLifecycleWrapper#destroy
 - DisposableBeanAdapter#run
 - ScheduledAnnotationBeanPostProcessor#postProcessBeforeDestruction会将TestController里面的任务全部cancel掉。
 
ScheduledAnnotationBeanPostProcessor#postProcessBeforeDestruction
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) {
        Set<ScheduledTask> tasks;
        synchronized (this.scheduledTasks) {
            tasks = this.scheduledTasks.remove(bean);
        }
        if (tasks != null) {
            for (ScheduledTask task : tasks) {
                task.cancel();
            }
        }
    }

取消核心流程GenericScope#destroy()
    public void destroy() {
        List<Throwable> errors = new ArrayList<Throwable>();
        Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
        for (BeanLifecycleWrapper wrapper : wrappers) {
            try {
                Lock lock = this.locks.get(wrapper.getName()).writeLock();
                lock.lock();
                try {
                    wrapper.destroy();
                }
                finally {
                    lock.unlock();
                }
            }
            catch (RuntimeException e) {
                errors.add(e);
            }
        }
        if (!errors.isEmpty()) {
            throw wrapIfNecessary(errors.get(0));
        }
        this.errors.clear();
    }
2.1 ThreadPoolTaskScheduler在哪里配置的?
ThreadPoolTaskScheduler
- 构造bean:nacosWatch:NacosWatch时会创建一个
 - 构造bean:taskScheduler:ThreadPoolTaskScheduler
 

public class TaskSchedulingAutoConfiguration {
    @Bean
    @ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
    @ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class })
    public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
        return builder.build();
    }
    @Bean
    @ConditionalOnMissingBean
    public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties,
            ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
        TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
        builder = builder.poolSize(properties.getPool().getSize());
        Shutdown shutdown = properties.getShutdown();
        builder = builder.awaitTermination(shutdown.isAwaitTermination());
        builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
        builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
        builder = builder.customizers(taskSchedulerCustomizers);
        return builder;
    }
2.2 TestController改造成ApplicationListener<RefreshScopeRefreshedEvent>
这样做为什么能够保证定时任务正常执行?
- RefreshScope#refreshAll
 - 发布RefreshScopeRefreshedEvent事件
 - 调用到TestController代理对象#onApplicationEvent
 - CglibAopProxy.DynamicAdvisedInterceptor#intercept
 - SimpleBeanTargetSource#getTarget
 - AbstractBeanFactory#getBean获取scopedTarget.testController
 - GenericScope#get
 - 会创建真正的TestController实例,然后初始化后调用ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization找出TestController中加了@Scheduled注解的方法
 - TestController#onApplicationEvent
 - this.execute();
 - 真正调用的是ReschedulingRunnable#run
 
以上就是@Scheduled定时器原理及@RefreshScope相互影响的详细内容,更多关于Scheduled定时器RefreshScope的资料请关注其它相关文章!
	声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
		
评论(0)