目录
方法一:使用Spring Profiles
1.1 步骤1
1.2 步骤2
1.3 步骤3
1.4 步骤4
方法二:使用@ConditionalOnProperty
2.1 步骤1
2.2 步骤2
2.3 步骤3
方法三: 主启动类禁用@EnableScheduling
定时任务原理剖析(选看)
1. @EnableScheduling的作用
2. @Scheduled的解析
解析过程
3. 任务调度与执行
调度机制
调度器实现
任务执行流程
4. 异常处理
在一些复杂项目中,我们写了很多定时任务类,但是有的时候,在代码调试阶段,不希望执行这些定时任务,如何更高效的方式关闭这些定时任务,而不是逐一注释代码。
解决方式也很简单。以下列举几种:
方法一:使用Spring Profiles
你可以为不同的环境(如开发、测试和生产)定义不同的profiles,并根据当前激活的profile来决定是否执行定时任务。
1.1 步骤1
在你的application.properties
文件中,定义一个profile-specific的属性,例如
# application.properties
spring.profiles.active=dev
1.2 步骤2
创建profile-specific的配置文件,例如application-dev.properties
,并在其中指定是否执行定时任务。
1.3 步骤3
在定时任务类上添加@Profile
注解,只在特定profile下才加载定时任务Bean:
@Component
@Profile("prod") // 只有在prod profile下才加载这个bean
public class ScheduledTasks {
@Scheduled(cron = "0 * * * * ?")
public void reportCurrentTime() {
System.out.println(new Date());
}
}
1.4 步骤4
当你需要关闭定时任务时,只需更改激活的profile,比如在application.properties
中设置
spring.profiles.active=test
方法二:使用@ConditionalOnProperty
还可以通过
@ConditionalOnProperty
注解来控制定时任务的启用与否。这要求在
application.properties
或application.yml
中定义一个属性,用来标识是否启用定时任务。
2.1 步骤1
在配置文件中添加一个属性
# application.properties
app.enableScheduledTasks=true
2.2 步骤2
在定时任务类上使用@ConditionalOnProperty
@Component
@ConditionalOnProperty(name = "app.enableScheduledTasks", havingValue = "true")
public class ScheduledTasks {
@Scheduled(cron = "0 * * * * ?")
public void reportCurrentTime() {
System.out.println(new Date());
}
}
2.3 步骤3
要禁用定时任务,只需将配置文件中的app.enableScheduledTasks
设置为false
即可。
方法三: 主启动类禁用@EnableScheduling
最简单的方式,就是将@EnableScheduling注解放在主启动类上,通过是否注释掉该注解,来决定是否禁用定时任务。推荐用这种方式!!!
同样的道理,像Rocketmq这种消息中间件也可以参考这些处理方式,进行统一开关。万变不离其宗~
定时任务原理剖析(选看)
Spring框架中的定时任务功能主要通过@Scheduled
注解来实现,其背后有一套完整的机制来支持定时任务的定义、调度和执行。下面将详细介绍@Scheduled
定时任务的实现原理。
1. @EnableScheduling
的作用
首先,要使用Spring的定时任务功能,需要在Spring配置类中添加@EnableScheduling
注解。这会触发一系列的内部配置动作:
- 自动配置:
@EnableScheduling
会自动配置AnnotationAwareTaskSchedulerAutoConfiguration
类,该类会为应用程序提供一个TaskScheduler
的实现,默认情况下是ConcurrentTaskScheduler
。 - 注册调度器:通过
SchedulingConfigurerSupport
类中的configureTasks
方法,将TaskScheduler
注册到ApplicationContext
中。
2. @Scheduled
的解析
当Spring容器启动时,会扫描所有带有@Component
及其派生注解(如@Service
、@Controller
等)的类,并初始化它们作为Bean。此时,Spring会检查这些Bean中的方法是否有@Scheduled
注解。
解析过程
- BeanPostProcessor:Spring框架使用了
BeanPostProcessor
机制来处理带有@Scheduled
注解的方法。具体来说,ScheduledAnnotationBeanPostProcessor
实现了BeanPostProcessor
接口,它会在Bean初始化之后(即postProcessAfterInitialization
方法)拦截这些Bean,并处理它们的方法上的@Scheduled
注解。 - 方法提取:
ScheduledAnnotationBeanPostProcessor
会提取所有带有@Scheduled
注解的方法,并创建一个ScheduledMethodRunnable
对象来包装这些方法。 - 任务注册:对于每一个
ScheduledMethodRunnable
对象,ScheduledAnnotationBeanPostProcessor
会将其注册到之前配置好的TaskScheduler
中,同时传递调度规则(如cron表达式或固定延迟)。
3. 任务调度与执行
调度机制
TaskScheduler
是Spring框架中用于调度任务的核心接口。它提供了两种主要的调度方式:
- 基于cron表达式:使用
cron
参数来定义调度规则。 - 基于固定延迟或周期:使用
fixedDelay
或fixedRate
参数来定义任务执行的时间间隔。
调度器实现
TaskScheduler
接口的具体实现通常由ConcurrentTaskScheduler
提供,后者内部使用ThreadPoolTaskScheduler
来管理任务的执行。ThreadPoolTaskScheduler
是一个实现了TaskScheduler
接口的类,它使用一个线程池来执行任务。
任务执行流程
当达到任务定义的执行时间时,TaskScheduler
会从线程池中获取一个线程来执行已注册的任务。任务执行的具体逻辑由ScheduledMethodRunnable
对象的run
方法完成。
4. 异常处理
如果@Scheduled
方法抛出了未捕获的异常,Spring会默认记录日志,并继续执行后续的任务调度。如果需要自定义异常处理逻辑,可以在方法内部进行异常捕获和处理。