我正在尝试定期在Spring MVC应用程序中运行一些工作。根据在线教程,我按如下方式设置了预定作业:
这是AppInitializer(我没有在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秒运行一次。我无法理解为什么会这样。我之前查看了有关此主题的问题,但我找不到匹配的解决方案。
其他帖子建议在这种情况下,bean可能会被初始化两次,但根据我的配置,我不确定是怎么回事。
Similar Question 上面的这个问题似乎与我要问的内容完全相同,但是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
根据Jennifer的建议,我确实看到两个实例正在调用run方法。
EDIT-2
M.Deinum的猜测绝对正确,我的MvcConfig.java由@ComponentScan注释,这使得Schedule Job运行了两次。但是在从MvcConfig.java中删除该注释后,我的终点停止了工作。我在这里错过了什么..
答案 0 :(得分:2)
当您创建Scheduled
类(ScheduledJobService
)的多个实例时,通常会发生这种情况。一个常见的原因是Spring上下文不止一次被创建。
将此添加到run方法以查看是否有多个实例:
public void run() {
System.out.println(this + " Current time is :: " + Calendar.getInstance().getTime());
}
您将能够在输出中看到它是否有多个实例。
要确保它不是属性值,请尝试不使用10000的硬编码值。
@Scheduled(fixedDelay = 10000)
答案 1 :(得分:1)
问题是您可能在JPAConfiguration
和MvcConfig
中都进行了相同的组件扫描。结果是你基本上都在加载你的整个应用程序两次(所以除非你想要内存问题,奇怪的事务问题等,这是要走的路)。
你想要的是你的ContextLoaderListener
(根上下文)加载除了与web相关的bean之外的所有东西,而DispatcherServlet
应该只加载与web相关的bean(视图,控制器,建议等)。
@ComponentScan
具有您可以控制此属性的属性。在JPAConfiguration
添加excludeFilters
上的MvcConfig
,停用默认值并添加一些includeFilters
。
@ComponentScan
的{{1}}应包含以下内容:
JPAConfiguration
您的@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)。