springboot2.x基础教程:@Scheduled开启定时任务及源码分析

在项目开发过程中,我们经常需要执行具有周期性的任务,通过定时任务可以很好的帮助我们实现。
常见的定时任务有JDK自带的TimeTask,ScheduledExecutorService,第三方的quartz框架,elastic-job等。
今天要给大家介绍的是SpringBoot自带的定时任务框架,通过@Scheduled注解就能很方便的开启一个定时任务。
Spring Schedule框架功能完善,简单易用。对于中小型项目需求,Spring Schedule是完全可以胜任的。

TimeTask,Spring-Schedule,Quartz对比

SpringBoot配置定时任务

SpringBoot开启一个定时任务非常简单,在方法上加上@Scheduled注解跟配合@EnableScheduling注解开启就能够开启一个定时任务。
这里的cron表达式可参考前面的文章:linux 定时任务crontab命令详解

@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---固定间隔执行,从上一次执行任务的结束时间开始算-------");
    }
}

配置定时任务线程池

在实际项目中,我们一个系统可能会定义多个定时任务。那么多个定时任务之间是可以相互独立且可以并行执行的。Spring Sheduld默认会创建一个单线程池执行定时任务。
这样对于我们的多任务调度可能会是致命的,当多个任务并发(或需要在同一时间)执行时,任务调度器就会出现时间漂移,任务执行时间将不确定。所以我们通常给定时任务自定义配置一个线程池。

@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;
    }
}

定时任务源码解析

SpringBoot加上@EnableScheduling注解配合@Scheduled就能生成定时任务,背后的源码带大家分析一遍。

扫描定时任务

@EnableScheduling注解引入了SchedulingConfiguration类,@Import具体作用见文章springboot2.x基础教程:@Enable*原理

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

SchedulingConfiguration又引入了ScheduledAnnotationBeanPostProcessor类,核心的流程在该类中。

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


该类继承了BeanPostProcessor接口是Spring IOC容器给我们提供的一个扩展接口。

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

因此在该类初始化bean后执行postProcessAfterInitialization方法,扫描容器中Bean带有@scheduled注解的方法,并通过processScheduled解析。


processScheduled会解析前面提到的cron、fixedDelay、fixedRate等属性,创建不同的类型的Task,加入scheduledTasks变量中。
image

触发定时任务

  1. 在容器发出ContextRefreshedEvent事件时,事件监听方法会调用finishRegistration()方法
  2. finishRegistration()会调用registrar.afterPropertiesSet()方法
  3. afterPropertiesSet()方法调用scheduleTasks();
    image
  4. scheduleTasks方法依次调用各个定时任务,这里也验证了不配置线程池,默认是单线程执行。
    image

    以上就是对springboot定时任务简单的分析,看完后发现还是很简单的。我们学习springboot源码学习的是优秀的设计方法,通过理解、模仿、从而创新,自己的编程功底才能进一步提升。
    千里之行,始于足下。这里是SpringBoot教程系列第十三篇,所有项目源码均可以在我的GitHub上面下载源码。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342