一、说明
版本号:SpringBoot 1.5.8.RELEASE
读者基础:用过SpringBoot定时任务
二、问题
启动类上面没有加上@EnableScheduling,只是在方法里面声明了一个@Scheduled,但是这个方法是有效的,是能够定时运行的。
相关代码
代码如下,这个是抽象类,它的子类的定时任务都可以正常运行。(并没有加@EnableScheduling)
三、排查-看源码
带着疑惑看看源码, 看下这个@EnableScheduling和@Schedule是如何配合的。
1. @Scheduled
从@Scheduled可以看出注解如果需要被执行,是需要这个ScheduledAnnotationBeanPostProcessor对象的。
而这个对象的生成有三种方法。
第一种:自己手动创建。
第二种:通过这个task:annotation-driven/ XML标签。
第三种:使用@EnableScheduling注解。
生成这个PostProcessor对象有以上三种方法。但是我的代码里面这上面的三种方式我都没有实现。所以并不是因为我自己的代码自己创建了对象,而使得定时任务可以运行的。于是我就再看看@EnableScheduling这个注解,看有没有什么特别的地方。
2. @EnableScheduling
看源码注释可以看出,这个EnableScheduling的作用和前面的XML标签是一样的,是一个开关,用来开启定时任务的。
再看看这里面导入了一个SchedulingConfiguration.class。点进去看一下,实际上他也是注册一个ScheduleAnnotationBeanPostProcessor对象,来处理@Scheduled注解。
上面的源码能够让我们知道@EnableScheduling和@Scheduled的关系。不过并无法回答为什么代码里面不写@EnableScheduling也能运行的原因。于是上网搜索。
四、排查-网络解答
通过网上搜索答案,在Springboot的github项目上,找到了这样的一个issued。
说的是actuator这个依赖里的MetriExportAutoConfiguration包含了EnableScheduling这个注解。
于是我去看看源码,目前我的这个1.5.8版本的actuator确实如此。
为了验证是否确实是这个问题导致,我把actuator的依赖去掉,果然,我把actuator去掉后,定时任务不会执行了。
所以能够锁定这个问题是由于
这个版本(1.5.8)actuator的 MetricExportAutoConfiguration包含了
@EnableScheduling,所以就算我们在自己的代码里面没有写这个注解,实际上定时任务也能够运行。
那这个不太合理,会存在一个问题。假设在一个项目里面,我想关闭掉原先在运行的定时任务,于是我把@EnableScheduling的注解去掉了,以为万事大吉。结果还是一样在运行。
新版本是否存在这个问题
同样在这个issued里面,Spring组织的成员Snicoll说明了,在新版本的SpringBoot 2.X就不存在这个问题了。
验证一下Snicoll的说法。
我下载了一个2.X版本的SpringBoot,选择了2.1.4.RELEASE这个版本。
已经找不到这个MetricExportAutoConfiguration类了。和这个类名最匹配的是这个AppOpticsMetricsExportAutoConfiguration类。
确实没有@EnableScheduling。
代码运行起来后,若我们没有添加@EnableScheduling,定时任务是不会运行的。
五、 结论
1.5.8版本的SpringBoot不需要写@EnableScheduling也能够运行定时任务的原因是actuator里面有一个配置类(MetricExportAutoConfiguration),它已经声明了这个注解。这个问题在SpringBoot 2.X之后修复了。