Spring Boot 自动配置之 TaskScheduler
TaskScheduler 是什么?
TaskScheduler 是 Spring 的轻量级调度器,适合单机、轻量、简单的定时/周期任务。
典型场景:缓存清理、心跳检测、延迟任务、动态调度。
不适合:分布式唯一执行、大规模调度、需要持久化的任务。
Spring Boot 自动配置类
所在包:org.springframework.boot.autoconfigure.task
类名:TaskSchedulingAutoConfiguration
package org.springframework.boot.autoconfigure.task;import org.springframework.boot.LazyInitializationExcludeFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.TaskManagementConfigUtils;/*** {@link EnableAutoConfiguration Auto-configuration} for {@link TaskScheduler}.** @author Stephane Nicoll* @author Moritz Halbritter* @since 2.1.0*/
@ConditionalOnClass(ThreadPoolTaskScheduler.class)
@AutoConfiguration(after = TaskExecutionAutoConfiguration.class)
@EnableConfigurationProperties(TaskSchedulingProperties.class)
@Import({ TaskSchedulingConfigurations.ThreadPoolTaskSchedulerBuilderConfiguration.class,TaskSchedulingConfigurations.SimpleAsyncTaskSchedulerBuilderConfiguration.class,TaskSchedulingConfigurations.TaskSchedulerConfiguration.class })
public class TaskSchedulingAutoConfiguration {/*** 条件注解,用于判断容器中是否存在指定名称的Bean* * 该注解基于Spring框架的条件化配置机制,只有当Spring容器中存在名称为* TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME的Bean时,* 相关的配置类或Bean才会被加载到容器中* * 主要用途:* - 确保定时任务相关的处理器Bean已存在* - 避免在缺少必要组件时加载相关配置* - 实现条件化的Bean注册和配置加载*/@Bean@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)public static LazyInitializationExcludeFilter scheduledBeanLazyInitializationExcludeFilter() {return new ScheduledBeanLazyInitializationExcludeFilter();}}
只有当 Spring 容器中存在名称为
“org.springframework.context.annotation.internalScheduledAnnotationProcessor” 的Bean时, 相关的配置类或 Bean才 会被加载到容器中,默认情况下此名称的 Bean 是不会被加载到容器中的。而加载的动作是由开关(@EnableScheduling 注解)来完成的。
通过注解来开启 TaskSchedule 的自动配置(开关)
注解:@EnableScheduling
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;@SpringBootApplication
/*** 启用Spring的定时任务调度功能* * 该注解用于开启Spring框架的定时任务支持,配合@Scheduled注解使用* 可以在方法上使用@Scheduled来定义定时执行的任务* * 使用示例:* @EnableScheduling* public class ScheduleConfig {* @Scheduled(fixedRate = 5000)* public void scheduledTask() {* // 定时执行的业务逻辑* }* }* * 注意事项:* 1. 需要配合@Configuration注解使用* 2. 被@Scheduled注解的方法必须是无参的public方法* 3. 可以通过配置线程池来控制并发执行*/
@EnableScheduling
public class DemoApplication {public static void main(String[] args) {new SpringApplicationBuilder().web(WebApplicationType.SERVLET).sources(DemoApplication.class).main(DemoApplication.class).run(args);}}
@EnableScheduling 能用在任何 Spring 管理的类上,包括 @Component、@Configuration。
不过推荐放在配置类(@Configuration)上,保持语义清晰。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {}
可以看到 @EnableScheduling 注解通过 @Import 导入了 SchedulingConfiguration 类,此类会被 Spring 生成一个名称为 “org.springframework.context.annotation.internalScheduledAnnotationProcessor” 的 Bean 并被注入到 Spring 容器中,而这个 Bean 正是我们上文中提到的 自动配置 TaskSchedule 的条件 Bean。
@Configuration(proxyBeanMethods = false)
@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();}}
使用自动配置的 TaskSchedule
具体的自动配置的类:org.springframework.boot.autoconfigure.task.TaskSchedulingConfigurations
自动配置的 bean 代码如下:
@Configuration(proxyBeanMethods = false)@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)@ConditionalOnMissingBean({ TaskScheduler.class, ScheduledExecutorService.class })static class TaskSchedulerConfiguration {@Bean(name = "taskScheduler")@ConditionalOnThreading(Threading.VIRTUAL)SimpleAsyncTaskScheduler taskSchedulerVirtualThreads(SimpleAsyncTaskSchedulerBuilder builder) {return builder.build();}@Bean@ConditionalOnThreading(Threading.PLATFORM)ThreadPoolTaskScheduler taskScheduler(ThreadPoolTaskSchedulerBuilder threadPoolTaskSchedulerBuilder) {return threadPoolTaskSchedulerBuilder.build();}}
从以上代码可以看出自动配置的 Bean 的名称是 “taskScheduler” , 具体类型因使用的线程类型而不同。
package com.example.demo.adapter.scheduler;import java.time.Instant;
import java.time.temporal.ChronoUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class SchedulerTest {/*** 使用方式一: 自动注入的任务调度器实例 用于执行定时任务和异步任务调度*/@Autowiredprivate TaskScheduler taskScheduler;public void schedule1() {taskScheduler.schedule(() -> {System.out.println("Scheduled task executed");}, Instant.now().plus(5, ChronoUnit.SECONDS));}/*** 使用方式二: 定时任务注解,用于标记一个方法作为定时执行的任务** @param initialDelay 任务首次执行前的延迟时间,单位为毫秒,此处设置为5000毫秒(5秒) * 重要说明:此注解标记的方法将在应用启动后延迟指定时间自动执行,通常用于需要在系统初始化完成后执行的后台任务或数据加载操作*/@Scheduled(initialDelay = 5000)public void schedule2() {System.out.println("Scheduled task executed");}}
使用 Spring Boot 自动配置的 TaskScheduler,通常有两种方式:
1、通过 @Autowired 注入 Bean;
2、使用 @Scheduled 注解,注意:被注解的方法必须是 : public 、package 、protected ,不能是 private 。另外请注意注释中的 【重要说明】以正确地使用此注解。
TaskScheduler 使用的线程池默认配置
TaskScheduler 背后使用的线程池为 ScheduledThreadPoolExecutor,默认参数如下:
- corePoolSize 核心线程数为 1;
- 队列为 DelayedWorkQueue,无界延迟队列;因为是无界,所以可以认为线程池中永远只有 corePoolSize 个线程;
- 最大线程数:Integer.MAX_VALUE,因为使用的是无界队列,所以这个参数意义不大;
- awaitTermination ,默认 false;
- threadNamePrefix,线程名称前缀,默认 “scheduling-”。
可以通过 application.yml 配置文件来更改这些默认配置,比如:
spring:task:scheduling:pool:size: 5 # 线程池大小,默认是 1thread-name-prefix: my-scheduler- # 线程名前缀,方便日志排查shutdown:await-termination: true # 应用关闭时是否等待任务完成await-termination-period: 30s # 最长等待时间
或通过实现 ThreadPoolTaskSchedulerCustomizer 接口来自定义配置参数,
import org.springframework.boot.task.ThreadPoolTaskSchedulerCustomizer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;/*** TaskSchedulerCustomizer 类用于自定义线程池任务调度器的配置*/
@Component
public class TaskSchedulerCustomizer implements ThreadPoolTaskSchedulerCustomizer {@Overridepublic void customize(ThreadPoolTaskScheduler taskScheduler) {taskScheduler.setPoolSize(2);}}
注:Spring Boot 版本为 3.5.5