在开发系统时,有时候我们会碰到一些需求,需要由定时任务来完成。SpringBoot开启定时任务很简单。由 @EnableScheduling 和 @Scheduled 来完成。
启动
@SpringBootApplication
@EnableScheduling
public class DatApplication {
public static void main(String[] args) {
SpringApplication.run(DatApplication.class, args);
}
}
定时任务
@Component
@Slf4j
public class TestTask {
@Scheduled(cron = "0 0 5 * * ?")
public void scheduledTask() {
System.out.println("定时任务执行了");
}
}
注意点:@Scheduled 注解的方法不能为 priavte、不能带参数。
扩展点
默认定时任务配置线程池核心大小为1,我可以自己配置定时任务线程池。
@Configuration
public class TaskConfig {
@Bean
public SchedulingConfigurer schedulingConfigurer() {
return taskRegistrar -> {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("task-schedule-pool-%d").build();
ThreadPoolExecutor taskPool = new ScheduledThreadPoolExecutor(5, threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
taskPool.setMaximumPoolSize(20);
taskPool.setKeepAliveTime(20, TimeUnit.SECONDS);
taskRegistrar.setScheduler(taskPool);
};
}
}
源码
@EnableScheduling的作用
@EnableScheduling 注解主要用来导入配置类 SchedulingConfiguration。那 SchedulingConfiguration 类又有什么有呢。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({SchedulingConfiguration.class})
@Documented
public @interface EnableScheduling {
}
SchedulingConfiguration 的作用
SchedulingConfiguration 是个配置类,用来配置定时任务解析类 ScheduledAnnotationBeanPostProcessor。
@Configuration(
proxyBeanMethods = false
)
@Role(2)
public class SchedulingConfiguration {
public SchedulingConfiguration() {
}
@Bean(
name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
)
@Role(2)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
ScheduledAnnotationBeanPostProcessor 的作用
ScheduledAnnotationBeanPostProcessor 是一个后置处理类,实现了 BeanPostProcessor 接口,该类主要用来解析有 @Scheduled 注解的类。在方法 postProcessAfterInitialization 内进行解析,主要逻辑是:找到有 @Scheduled 注解的标记的方法(可以有多个),然后把 @Scheduled 标记的方法解析成 任务 (CronTask,FixedDelayTask,FixedRateTask),最后把这些 任务 交给 ScheduledTaskRegistrar 处理。
public Object postProcessAfterInitialization(Object bean, String beanName) {
// bean不属于以下三种类型
if (!(bean instanceof AopInfrastructureBean) && !(bean instanceof TaskScheduler) && !(bean instanceof ScheduledExecutorService)) {
// 获取bean的原始Class,bean有可能是被代理的。
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
// bean类必须有 @Schedules注解
if (!this.nonAnnotatedClasses.contains(targetClass) && AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {
// 获取被@Schedules标记的方法,一个方法可以被多个@Schedules标记
// @Schedules注解是可重复的
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, (method) -> {
Set<Scheduled> scheduledAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
return !scheduledAnnotations.isEmpty() ? scheduledAnnotations : null;
});
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(targetClass);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
}
} else {
// 遍历,并Method和@Scheduled封装成任务
annotatedMethods.forEach((method, scheduledAnnotations) -> {
scheduledAnnotations.forEach((scheduled) -> {
// 解析任务
this.processScheduled(scheduled, method, bean);
});
});
if (this.logger.isTraceEnabled()) {
this.logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': " + annotatedMethods);
}
}
}
return bean;
} else {
return bean;
}
}
执行流

本文介绍了如何在SpringBoot中利用@EnableScheduling和@Scheduled创建定时任务,包括启动步骤、任务实现和自定义定时任务线程池配置。重点讲解了@EnableScheduling注解的作用和SchedulingConfiguration类在定时任务解析中的关键角色。
873

被折叠的 条评论
为什么被折叠?



