@Scheduled定時器原理及@RefreshScope相互影響
1.ScheduledAnnotationBeanPostProcessor
@EnableScheduling
- @Import(SchedulingConfiguration.class)
- 注冊了ScheduledAnnotationBeanPostProcessor
@RestController @RefreshScope //動態(tài)感知修改后的值 public class TestController implements ApplicationListener<RefreshScopeRefreshedEvent>{ @Value("${common.age}") String age; @Value("${common.name}") String name; @GetMapping("/common") public String hello() { return name+","+age; } //觸發(fā)@RefreshScope執(zhí)行邏輯會導致@Scheduled定時任務失效 @Scheduled(cron = "*/3 * * * * ?") //定時任務每隔3s執(zhí)行一次 public void execute() { System.out.println("定時任務正常執(zhí)行。。。。。。"); } @Override public void onApplicationEvent(RefreshScopeRefreshedEvent event) { this.execute(); } }
1.1 SmartInitializingSingleton#afterSingletonsInstantiated
ScheduledAnnotationBeanPostProcessor#afterSingletonsInstantiated
- DefaultListableBeanFactory#preInstantiateSingletons
- SmartInitializingSingleton#afterSingletonsInstantiated
- 沒干啥重要事情
1.2 RefreshScope處理ContextRefreshedEvent創(chuàng)建refresh中的bean
并調用ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization找出TestController中加了@Scheduled注解的方法。
ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization
- 發(fā)布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
- 開始執(zhí)行任務,這cronTasks不為空,則執(zhí)行該任務
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配置中心發(fā)布配置時,會調用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時會創(chuàng)建一個
- 構造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>
這樣做為什么能夠保證定時任務正常執(zhí)行?
- RefreshScope#refreshAll
- 發(fā)布RefreshScopeRefreshedEvent事件
- 調用到TestController代理對象#onApplicationEvent
- CglibAopProxy.DynamicAdvisedInterceptor#intercept
- SimpleBeanTargetSource#getTarget
- AbstractBeanFactory#getBean獲取scopedTarget.testController
- GenericScope#get
- 會創(chuàng)建真正的TestController實例,然后初始化后調用ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization找出TestController中加了@Scheduled注解的方法
- TestController#onApplicationEvent
- this.execute();
- 真正調用的是ReschedulingRunnable#run
以上就是@Scheduled定時器原理及@RefreshScope相互影響的詳細內容,更多關于Scheduled定時器RefreshScope的資料請關注腳本之家其它相關文章!
相關文章
在IntelliJ IDEA中多線程并發(fā)代碼的調試方法詳解
這篇文章主要介紹了在IntelliJ IDEA中多線程并發(fā)代碼的調試方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08