解析 Spring 计划任务执行多次之谜及解决方案
在Spring
项目中,计划任务(Scheduled Tasks
)是一种常用的功能,用于定期执行特定操作。然而,在实际使用过程中,可能会遇到计划任务执行多次的现象。本文将深入探讨这一现象背后的原因,并提供有效的解决方案。
一、现象描述
在Spring
项目中,我们定义了一个计划任务类ScheduledTaskParent
,以及两个继承该类的子类FirstChild
和SecondChild
。
1 |
|
当应用启动后,发现ScheduledTaskParent
中的计划任务被执行了多次,具体表现为每个子类实例都执行了父类的计划任务,导致执行次数为子类数目加1。
1 | FirstChild 执行特定的操作 |
二、原因分析
1. 继承关系导致的问题
在Java
中,子类会继承父类的所有属性和方法。在本例中,FirstChild
和SecondChild
继承了ScheduledTaskParent
类,同时也继承其计划任务方法。由于,ScheduledTaskParent
和其子类都被标记为@Component
,Spring
容器会将它们都注册为Bean
,并调度其中的计划任务。
根据Spring
官方文档,组件扫描会自动检测Bean
,无需手动注册。这意味着,如果父类中有@Scheduled
注解的方法,它会被视为一个独立的Bean
并执行,而子类同样会执行这些继承来的方法。
Spring’s component scanning feature enables you to automatically detect your beans, as opposed to manually registering them. This feature is particularly useful when you are developing larger applications because it lets you define beans with annotations and without having to write any XML configuration.
2. Spring 容器管理问题
Spring
官方文档指出,要使用计划任务功能,需要在配置类中声明@EnableScheduling
。这会使得Spring
容器检测所有Spring
管理的Bean
中的@Scheduled
注解,并将它们作为计划任务调度。因此,如果父类和子类都被注册为Bean
,它们的方法都会被调度,导致重复执行。
To use this capability, you must declare @EnableScheduling in one of your @Configuration classes. This will enable detection of @Scheduled annotations on any Spring-managed bean in the container.
三、解决方案
为了防止计划任务在子类中被重复执行,我们可以在父类中定义一个抽象方法,并在子类中实现具体的计划任务。如下所示:
1 | public abstract class ScheduledTaskParent { |
通过这种方式,每个子类只负责自己的计划任务,而不会继承父类的计划任务。
Title: 解析 Spring 计划任务执行多次之谜及解决方案
Author: Amber
Date: 2022-04-01
Last Update: 2024-10-22
Blog Link: https://wyiyi.github.io/amber/2022/04/01/Scheduled/
Copyright Declaration: Copyright © 2022 Amber.