SpringBoot定时任务@Scheduled注解详解

SpringBoot定时任务@Scheduled注解详解
SpringBoot定时任务@Scheduled注解详解
 
项目开发中,经常会遇到定时任务的场景,Spring提供了@Scheduled注解,方便进行定时任务的开发
 
概述
 
要使用@Scheduled注解,首先需要在启动类添加@EnableScheduling,启用Spring的计划任务执行功能,这样可以在容器中的任何Spring管理的bean上检测@Scheduled注解,执行计划任务
 
注解定义
 
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
 
@Retention(RetentionPolicy.RUNTIME)
 
@Documented
 
@Repeatable(Schedules.class)
 
public @interface Scheduled {
 
String cron() default "";
 
String zone() default "";
 
long fixedDelay() default -1;
 
String fixedDelayString() default "";
 
long fixedRate() default -1;
 
String fixedRateString() default "";
 
long initialDelay() default -1;
 
String initialDelayString() default "";
 
}
 
参数说明
 
参数 参数说明 示例
 
cron 任务执行的cron表达式 0/1 * * * * ?
 
zone cron表达时解析使用的时区,默认为服务器的本地时区,使用java.util.TimeZone#getTimeZone(String)方法解析 GMT-8:00
 
fixedDelay 上一次任务执行结束到下一次执行开始的间隔时间,单位为ms 1000
 
fixedDelayString 上一次任务执行结束到下一次执行开始的间隔时间,使用java.time.Duration#parse解析 PT15M
 
fixedRate 以固定间隔执行任务,即上一次任务执行开始到下一次执行开始的间隔时间,单位为ms,若在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后立即执行下一次任务 2000
 
fixedRateString 与fixedRate逻辑一致,只是使用java.time.Duration#parse解析 PT15M
 
initialDelay 首次任务执行的延迟时间 1000
 
initialDelayString 首次任务执行的延迟时间,使用java.time.Duration#parse解析 PT15M
 
源码解析
 
配置了@Scheduled注解的方法,Spring的处理是通过注册ScheduledAnnotationBeanPostProcessor来执行,将不同配置参数的任务分配给不同的handler处理,核心代码如下
 
org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization
 
@Override
 
public Object postProcessAfterInitialization(Object bean, String beanName) {
 
if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||
 
bean instanceof ScheduledExecutorService) {
 
// Ignore AOP infrastructure such as scoped proxies.
 
return bean;
 
}
 
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
 
if (!this.nonAnnotatedClasses.contains(targetClass) &&
 
AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {
 
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
 
(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
 
Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
 
method, Scheduled.class, Schedules.class);
 
return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
 
});
 
if (annotatedMethods.isEmpty()) {
 
this.nonAnnotatedClasses.add(targetClass);
 
if (logger.isTraceEnabled()) {
 
logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
 
}
 
}
 
else {
 
// Non-empty set of methods
 
annotatedMethods.forEach((method, scheduledMethods) ->
 
scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));
 
if (logger.isTraceEnabled()) {
 
logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName +
 
"': " + annotatedMethods);
 
}
 
}
 
}
 
return bean;
 
}

推荐阅读