Spring 调度:@Controller 注释的 class 中的方法上的 @Scheduled 注释运行两次
Spring Scheduling: @Scheduled annotation on a method inside a class annotated with @Controller runs twice
考虑以下代码片段:
@Controller
public class RestController {
@Scheduled(cron = "0 0 */* * * ?") // run every hour
public void runMeHourly() {
LOGGER.debug("RestController#runMeHourly triggered to run at: " + System.currentTimeMillis());
// Do your hourly work here
}
}
当我在 J2EE Web 服务器中部署此控制器时,我发现 RestController#runMeHourly()
方法每小时触发两次。
我在 spring docs scheduling 上找到了对类似内容的引用。
它说:
Make sure that you are not initializing multiple instances of the same @Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use @Configurable on bean classes which are annotated with @Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the @Configurable aspect, with the consequence of each @Scheduled method being invoked twice.
这有关系吗?这是否意味着我需要从 RestController
外部安排方法 runMeHourly()
?
[编辑 1:看起来 @Configurable 是其他东西,并没有导致问题,我没有在任何地方使用过它。所以一定有其他原因导致这种行为]
[编辑 2:
我的web.xml:
<web-app>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>com.company.module.ModuleContextListener</listener-class>
</listener>
</web.xml>
mvc-调度程序-servlet.xml
<beans>
<mvc:annotation-driven />
<task:annotation-driven />
<context:component-scan base-package="com.company" />
<import resource="module/module-servlet.xml"/>
</beans>
module/module-servlet.xml
<beans>
<context:component-scan base-package="com.company.module"/>
</beans>
]
com.company.module.ModuleContextListener
迫使 DispatcherServlet
寻找根应用程序上下文,并且由于根应用程序上下文与 mvc-dispatcher-servlet.xml
相同,因此它被加载了两次。一次作为根上下文,一次在 DispatcherServlet 下,名称为 mvc-dispatcher
.
将根上下文 xml mvc-dispatcher-servlet.xml
重命名为 applicationContext.xml
并添加一个空的 mvc-dispatcher-servlet.xml
解决了问题。
感谢@6ton 指出这一点。
考虑以下代码片段:
@Controller
public class RestController {
@Scheduled(cron = "0 0 */* * * ?") // run every hour
public void runMeHourly() {
LOGGER.debug("RestController#runMeHourly triggered to run at: " + System.currentTimeMillis());
// Do your hourly work here
}
}
当我在 J2EE Web 服务器中部署此控制器时,我发现 RestController#runMeHourly()
方法每小时触发两次。
我在 spring docs scheduling 上找到了对类似内容的引用。
它说:
Make sure that you are not initializing multiple instances of the same @Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use @Configurable on bean classes which are annotated with @Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the @Configurable aspect, with the consequence of each @Scheduled method being invoked twice.
这有关系吗?这是否意味着我需要从 RestController
外部安排方法 runMeHourly()
?
[编辑 1:看起来 @Configurable 是其他东西,并没有导致问题,我没有在任何地方使用过它。所以一定有其他原因导致这种行为]
[编辑 2:
我的web.xml:
<web-app>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>com.company.module.ModuleContextListener</listener-class>
</listener>
</web.xml>
mvc-调度程序-servlet.xml
<beans>
<mvc:annotation-driven />
<task:annotation-driven />
<context:component-scan base-package="com.company" />
<import resource="module/module-servlet.xml"/>
</beans>
module/module-servlet.xml
<beans>
<context:component-scan base-package="com.company.module"/>
</beans>
]
com.company.module.ModuleContextListener
迫使 DispatcherServlet
寻找根应用程序上下文,并且由于根应用程序上下文与 mvc-dispatcher-servlet.xml
相同,因此它被加载了两次。一次作为根上下文,一次在 DispatcherServlet 下,名称为 mvc-dispatcher
.
将根上下文 xml mvc-dispatcher-servlet.xml
重命名为 applicationContext.xml
并添加一个空的 mvc-dispatcher-servlet.xml
解决了问题。
感谢@6ton 指出这一点。