springboot2.x basic tutorial: @Scheduled opens timing tasks and source code analysis

In the process of project development, we often need to perform periodic tasks, and timing tasks can help us achieve this.
Common timing tasks include TimeTask, ScheduledExecutorService that comes with JDK, third-party quartz framework, elastic-job, etc.
Today I want to introduce to you the timed task framework that comes with SpringBoot. You can easily start a timed task through the @Scheduled annotation.
The Spring Schedule framework is fully functional and easy to use. For the needs of small and medium-sized projects, Spring Schedule is completely competent.

TimeTask,Spring-Schedule,Quartz对比

SpringBoot configuration timing task

It is very simple for SpringBoot to start a scheduled task. Adding @Scheduled annotation to the method and opening with @EnableScheduling annotation can start a scheduled task.
The cron expression here can refer to the previous article: linux timing task crontab command detailed

@Component
@EnableScheduling
@Slf4j
public class ScheduledTask {
    @Scheduled(cron = "*/1 * * * * ?")
    public void cronTask1(){
        log.info("CronTask-当方法的执行时间超过任务调度频率时,调度器会在下个周期执行");
        try {
            Thread.sleep(5100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Scheduled(fixedRate = 1000)
    public void cronTask2(){
        log.info("fixedRate--固定频率执行,当前执行任务如果超时,调度器会在当前方法执行完成后立即执行");
    }
    @Scheduled(fixedDelay = 1000)
    public void cronTask3(){
        log.info("fixedDelay---固定间隔执行,从上一次执行任务的结束时间开始算-------");
    }
}

Configure timed task thread pool

In actual projects, one system may define multiple timing tasks. Then multiple timing tasks can be mutually independent and can be executed in parallel. By default, Spring Sheduld creates a single-threaded pool to perform timing tasks.
This may be fatal to our multi-task scheduling. When multiple tasks are executed concurrently (or need to be executed at the same time), the task scheduler will drift in time and the task execution time will be uncertain. So we usually configure a thread pool for timing tasks.

@EnableScheduling
@Configuration
public class ScheduledTaskConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(taskExecutor());
    }

    public ThreadPoolTaskScheduler  taskExecutor() {
        ThreadPoolTaskScheduler scheduler=new ThreadPoolTaskScheduler();
        // 设置核心线程数
        scheduler.setPoolSize(8);
        // 设置默认线程名称
        scheduler.setThreadNamePrefix("CodehomeScheduledTask-");
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.initialize();
        return scheduler;
    }
}

Timing task source code analysis

SpringBoot plus @EnableScheduling annotation and @Scheduled can generate timed tasks. The source code behind will let you analyze it.

Scan timed tasks

The @EnableScheduling annotation introduces the SchedulingConfiguration class. For the specific function of @Import, see the article springboot2.x basic tutorial: @Enable* principle

@Import({SchedulingConfiguration.class})
public @interface EnableScheduling {
}

SchedulingConfiguration introduces the ScheduledAnnotationBeanPostProcessor class, and the core process is in this class.

@Configuration
public class SchedulingConfiguration {
    @Bean(
        name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
    )
    public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
        return new ScheduledAnnotationBeanPostProcessor();
    }
}


This class inherits the BeanPostProcessor interface, which is an extended interface provided by the Spring IOC container.

public interface BeanPostProcessor {
    //bean初始化方法调用前被调用
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //bean初始化方法调用后被调用
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

Therefore, the postProcessAfterInitialization method is executed after the bean is initialized by this class, and the method annotated with @scheduled in the bean in the container is scanned, and analyzed by processScheduled. processScheduled will parse the aforementioned cron, fixedDelay, fixedRate and other attributes, create different types of tasks, and add them to the scheduledTasks variable.


Trigger a scheduled task

  1. When the container emits the ContextRefreshedEvent event, the event listener method will call the finishRegistration() method
  2. finishRegistration() will call the registry.afterPropertiesSet() method
  3. afterPropertiesSet() method calls scheduleTasks();
  4. The scheduleTasks method calls each timed task in turn. It is also verified that the thread pool is not configured, and the default is single-threaded execution. The above is a simple analysis of springboot timing tasks. After reading it, it is still very simple. What we learn from the springboot source code is an excellent design method. Only by understanding, imitating, and innovating, can our programming skills be further improved. A thousand miles begins with a single step. This is the thirteenth article of the SpringBoot tutorial series. All project source codes can be downloaded on my GitHub .


Guess you like

Origin blog.csdn.net/github_35592621/article/details/108249528