Spring @Scheduled执行作业的次数比预期次数高出两倍



我正在尝试定期在我的Spring MVC应用程序中运行一些作业。根据在线教程,我按如下方式设置计划作业:

这是应用程序初始值设定项(我在XML中没有设置(:

public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();  
rootContext.register(JPAConfiguration.class);
servletContext.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
dispatcherServlet.register(MvcConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}

这是配置文件:

@Configuration
@EnableScheduling
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.prime.tutorials"})
@EnableJpaRepositories(basePackages = {"com.prime.tutorials.model", "com.prime.tutorials.repository"})
public class JPAConfiguration {
@Value("${jdbcURL}")
private transient String jdbcURL;
@Value("${dbPassword}")
private transient String dbPassword;
/* The usual stuff here, let me know if you want me post that as well */

}

这是处理计划作业的类:

@Service
public class ScheduledJobService {
@Autowired
private PrimeRepository primeRepository
@Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds:10000}")
public void run() {
System.out.println("Current time is :: " + Calendar.getInstance().getTime());
}
}

如您所见,固定延迟设置为 10 秒,但我的工作每 5 秒运行一次。我不明白为什么会这样。我之前浏览了有关此主题的问题,但无法找到匹配的解决方案。

其他帖子表明,在这种情况下,豆子可能会初始化两次,但根据我的配置,我不确定这是怎么回事。

类似问题 上面的这个问题似乎与我所问的完全重复,但 OP 尚未发布他/她的配置或设置。大多数答案都建议对组件进行双重初始化,我不确定我的应用程序是否适合这种情况。

Current time is :: Sun Jun 10 22:53:16 EDT 2018
Current time is :: Sun Jun 10 22:53:22 EDT 2018
Current time is :: Sun Jun 10 22:53:26 EDT 2018
Current time is :: Sun Jun 10 22:53:32 EDT 2018
Current time is :: Sun Jun 10 22:53:36 EDT 2018

编辑-1

根据詹妮弗的建议,我确实看到两个实例正在调用 run 方法。

编辑-2

M.Deinum的猜测是绝对正确的,我的MvcConfig.java被@ComponentScan注释,这使得计划作业运行了两次。但是从 MvcConfig 中删除该注释后.java我的端点停止工作。我在这里错过了什么..

问题是您的JPAConfigurationMvcConfig中可能具有相同的组件扫描。结果是你基本上加载了整个应用程序两次(所以除非你想遇到内存问题,奇怪的事务问题等,否则这是要走的路(。

你想要的是你的ContextLoaderListener(根上下文(加载除 Web 相关 bean 之外的所有内容,DispatcherServlet应该只加载与 Web 相关的 bean(视图、控制器、建议等(。

@ComponentScan具有可用于控制此属性的属性。在JPAConfiguration中添加一些excludeFiltersMvcConfig禁用默认值并添加一些includeFilters

您的JPAConfiguration@ComponentScan应包含以下内容:

@ComponentScan(
basePackages = {"com.prime.tutorials"},
excludeFilters = {
@ComponentScan.Filter( { Controller.class, ControllerAdvice.class })
})

您的MvcConfig您应该使用相同的includeFilters,并禁用默认过滤器。

@ComponentScan(
basePackages = {"com.prime.tutorials"},
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter( { Controller.class, ControllerAdvice.class })
})

您不想做不同的基本包,因为这会非常麻烦。恕我直言,您不应该使用技术分离作为创建包的一种方式(另请参阅 https://softwareengineering.stackexchange.com/questions/258196/java-application-structure-horizontal-vs-vertical-split/258197#258197(。

当您创建Scheduled类的多个实例 (ScheduledJobService( 时,通常会发生这种情况。一个常见的原因是 Spring 上下文被多次创建。

将此添加到 run 方法以查看您是否有多个实例:

public void run() {
System.out.println(this + " Current time is :: " + Calendar.getInstance().getTime());
}

您将能够在输出中看到其多个实例。

若要确保它不是属性值,请尝试不使用硬编码值 10000。

@Scheduled(fixedDelay = 10000)

最新更新