Spring @Scheduled注解方法(cron:0 */5 * * * *)执行两次问题求助
解决@Scheduled定时任务执行两次的问题
你找的方向完全没错——这个问题确实大概率是Spring上下文重复加载导致的。结合你给出的web.xml配置,咱们来拆解一下问题根源和解决办法:
首先得明确,Spring Web应用默认会存在两个上下文:
- 根上下文:由
ContextLoaderListener加载,对应你web.xml里<context-param>指定的mvc-config.xml - Servlet上下文:由
DispatcherServlet加载,如果没单独指定contextConfigLocation,它会默认去加载/WEB-INF/dispatcherServlet-servlet.xml
如果这两个上下文的配置文件里,重复扫描了带有@Scheduled注解的类,或者都启用了任务调度功能(比如xml里的<task:annotation-driven>或者注解的@EnableScheduling),就会导致同一个定时任务被初始化两次,自然就会执行两次。
具体解决方案:
拆分配置职责,避免重复扫描
把根上下文和Servlet上下文的配置职责明确分开:- 根上下文(建议把
mvc-config.xml改名为applicationContext.xml更清晰)负责加载业务层、数据层的Bean,比如service、dao包,并且在这里启用任务调度:<context:component-scan base-package="com.yourpackage.service, com.yourpackage.dao" /> <task:annotation-driven /> <!-- 在这里开启定时任务支持 --> - Servlet上下文(比如
dispatcherServlet-servlet.xml)只负责加载Web层的Bean,比如controller包,不要在这里启用任务调度:<context:component-scan base-package="com.yourpackage.controller" /> <!-- 不要加<task:annotation-driven>,避免重复初始化调度器 -->
- 根上下文(建议把
检查web.xml配置,杜绝重复加载同一配置
确认你的DispatcherServlet配置里没有指定和根上下文相同的contextConfigLocation,比如不要出现这样的错误配置:<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/mvc-config.xml</param-value> <!-- 这会导致和根上下文重复加载同一个配置 --> </init-param> </servlet>确认定时任务类的扫描范围
确保带有@Scheduled注解的类只被根上下文扫描到,不要让Servlet上下文也扫描到它所在的包。
按照这个思路调整配置后,定时任务应该就只会执行一次了。
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

