在开发系统时,有时候我们会碰到一些需求,需要由定时任务来完成。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;
}
}