您好,欢迎来到测品娱乐。
搜索
您的当前位置:首页spring定时任务原理

spring定时任务原理

来源:测品娱乐
spring定时任务原理

参考⽂章: https://juejin.im/post/5b448af265da0f7f44c201 https://juejin.im/post/5e338ebae51d45588b1ca01、开发中使⽤时要注意的点

  (0)spring定时任务执⾏原理实际使⽤的是 JDK ⾃带的 ScheduledExecutorService

  (1)spring默认使⽤单线程的线程池去执⾏定时任务,所以如果某个任务执⾏时间过长,会导致其他定时任务阻塞⽆法执⾏。  (2)可以开启并⾏调度,springboot中的使⽤⽅式:这种模式每次任务执⾏都会创建⼀个线程去执⾏。

@EnableAsync

@EnableScheduling@SpringBootApplication

public class QuickMediaApplication {

public static void main(String[] args) {

SpringApplication.run(QuickMediaApplication.class, args); }

@Scheduled(cron = \"0/1 * * * * ?\") @Async

public void sc1() {

System.out.println(Thread.currentThread().getName() + \" | sc1 \" + System.currentTimeMillis()); }}

  风险:如果某个定时任务出现死循环或者执⾏时间过长⽽出发时间较短,会导致线程数量不可控。  (3)最稳妥的处理⽅式:⾃定义任务执⾏的线程池,如下:  普通spring配置:

@Bean

public AsyncTaskExecutor asyncTaskExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setThreadNamePrefix(\"task-schedule-\"); executor.setMaxPoolSize(10); executor.setCorePoolSize(3); executor.setQueueCapacity(0);

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); return executor;}或

@Bean

public ScheduleExecutorService scheduleExecutorService{ return Executors.new ScheduleThreadPool(10); }

  springboot中配置:

spring.task.scheduling.pool.size=10

spring.task.scheduling.thread-name-prefix=task-schedule-

2、源码分析

  通过监听IOC容器初始化事件,扫描所有 Bean 中带有 @Scheduled 注解的⽅法,然后封装成 Task ⼦类放置到 ScheduledTaskRegistrar中。如果⾃⼰定义了ScheduledExecutorService,会使⽤⾃⼰定义的线程池,否则ScheduledTaskRegistrar#afterPropertiesSet 创建⼀个单线程的定时任务执⾏器ScheduledExecutorService,注⼊到 ConcurrentTaskScheduler中,然后通过 taskScheduler 执⾏定时任务。

public class ScheduledAnnotationBeanPostProcessor

implements ScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware, SmartInitializingSingleton, ApplicationListener, DisposableBean {  ................

@Override

public void onApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext() == this.applicationContext) {

// Running in an ApplicationContext -> register tasks this late...

// giving other ContextRefreshedEvent listeners a chance to perform // their work at the same time (e.g. Spring Batch's job registration). finishRegistration(); }

}

private void finishRegistration() { if (this.scheduler != null) {

this.registrar.setScheduler(this.scheduler); }

.......................if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {

Assert.state(this.beanFactory != null, \"BeanFactory must be set to find scheduler by type\"); try {

// Search for TaskScheduler bean...

this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, false)); }

catch (NoUniqueBeanDefinitionException ex) {

logger.debug(\"Could not find unique TaskScheduler bean\ try {

this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, true)); }

catch (NoSuchBeanDefinitionException ex2) { if (logger.isInfoEnabled()) {

logger.info(\"More than one TaskScheduler bean exists within the context, and \" +

\"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' \" + \"(possibly as an alias); or implement the SchedulingConfigurer interface and call \" +

\"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: \" + ex.getBeanNamesFound()); } } }

catch (NoSuchBeanDefinitionException ex) {

logger.debug(\"Could not find default TaskScheduler bean\ // Search for ScheduledExecutorService bean next... try {

this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, false)); }

catch (NoUniqueBeanDefinitionException ex2) {

logger.debug(\"Could not find unique ScheduledExecutorService bean\ try {

this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, true)); }

catch (NoSuchBeanDefinitionException ex3) { if (logger.isInfoEnabled()) {

logger.info(\"More than one ScheduledExecutorService bean exists within the context, and \" + \"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' \" + \"(possibly as an alias); or implement the SchedulingConfigurer interface and call \" +

\"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: \" + ex2.getBeanNamesFound()); } } }

catch (NoSuchBeanDefinitionException ex2) {

logger.debug(\"Could not find default ScheduledExecutorService bean\ // Giving up -> falling back to default scheduler within the registrar...

logger.info(\"No TaskScheduler/ScheduledExecutorService bean found for scheduled processing\"); } } }

this.registrar.afterPropertiesSet(); }}

if (this.taskScheduler == null) {

this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);}

1.

Spring 定时任务执⾏原理实际使⽤的是 JDK ⾃带的 ScheduledExecutorService

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- cepb.cn 版权所有 湘ICP备2022005869号-7

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务