是什么导致 Spring 调度程序在应用程序和 servlet 启动之前执行? [英] What causes Spring scheduler to execute before the application and servlet starts up?
问题描述
我有一个带有一些调度任务的简单 Spring-Boot Web 应用程序:
I have a simple Spring-Boot web application with some scheduling tasks:
@SpringBootApplication
@EnableScheduling
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder app) {
return app.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
还有一个服务执行两个调度任务:
And a service executing two scheduling tasks:
@Service
public class SchedulingService {
@Scheduled(fixedRate = 15000)
private void first() {
// log first
}
@Scheduled(fixedRate = 6000)
public void second() {
// log second
}
}
是否有任何解释可以说明为什么在应用程序和 servlet 启动之前执行了其中一项调度任务?这种情况反复发生并且日志顺序总是相同的,所以我怀疑没有发生多线程 - 第一个和第二个调度任务之间有将近一秒的差异.
Is there any explanation revealing why one of the scheduling tasks has been executed before the application and servlet starts up? This happens repeatedly and the log order is always the same, so I suspect the multithreading doesn't take place - there is nearly one-second difference between the first and the second scheduling task.
这是带有突出显示部分调度任务日志
的日志:
2018-08-18 20:47:53.085 INFO 251168 --- [ost-startStop-1] o.s.b.a.w.s.WelcomePageHandlerMapping:添加欢迎页面模板:index
2018-08-18 20:47:53.085 INFO 251168 --- [ost-startStop-1] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2018-08-18 20:47:53.300 INFO 251168 --- [ost-startStop-1] o.s.j.e.a.AnnotationMBeanExporter:在启动时注册用于 JMX 暴露的 bean
2018-08-18 20:47:53.300 INFO 251168 --- [ost-startStop-1] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-08-18 20:47:53.314 INFO 251168 --- [ost-startStop-1] s.a.ScheduledAnnotationBeanPostProcessor:未找到用于计划处理的 TaskScheduler/ScheduledExecutorService bean
2018-08-18 20:47:53.314 INFO 251168 --- [ost-startStop-1] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2018-08-18 20:47:53.321 这里首先登录
2018-08-18 20:47:53.344 INFO 251168 --- [ost-startStop-1] my.appname.Application:在 5.565 秒内启动应用程序(JVM 运行 16.93)
2018-08-18 20:47:53.344 INFO 251168 --- [ost-startStop-1] my.appname.Application : Started Application in 5.565 seconds (JVM running for 16.93)
2018-08-18 20:47:53.396 INFO 251168 --- [main] org.apache.coyote.ajp.AjpNioProtocol:启动 ProtocolHandler ["ajp-nio-8009"]
2018-08-18 20:47:53.396 INFO 251168 --- [ main] org.apache.coyote.ajp.AjpNioProtocol : Starting ProtocolHandler ["ajp-nio-8009"]
2018-08-18 20:47:53.400 INFO 251168 --- [main] org.apache.catalina.startup.Catalina:服务器启动时间为 15970 毫秒
2018-08-18 20:47:53.400 INFO 251168 --- [ main] org.apache.catalina.startup.Catalina : Server startup in 15970 ms
2018-08-18 20:47:53.477 INFO 251168 --- [nio-8080-exec-1] o.a.c.c.C.[.[localhost].[/Rattle]:初始化 Spring FrameworkServlet 'dispatcherServlet'
2018-08-18 20:47:53.477 INFO 251168 --- [nio-8080-exec-1] o.a.c.c.C.[.[localhost].[/Rattle] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-08-18 20:47:53.477 INFO 251168 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': 初始化开始
2018-08-18 20:47:53.477 INFO 251168 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2018-08-18 20:47:53.520 INFO 251168 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': 初始化在 43 毫秒内完成
2018-08-18 20:47:53.520 INFO 251168 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 43 ms
2018-08-18 20:47:54.103 这里记录第二次
2018-08-18 20:47:59.335 这里记录第二次
2018-08-18 20:48:05.334 这里记录第二次
2018-08-18 20:48:08.334 这里首先登录
推荐答案
我刚刚创建了一个空的 SpringBoot 项目,添加了您的类并尝试重现相同的问题.在 SpringBoot 2.0.4.RELEASE
上,我看到两个任务在同一时间和同一线程上运行:
I just created an empty SpringBoot project, added your class and tried to reproduce the same issue.
On SpringBoot 2.0.4.RELEASE
I see that both tasks run at the same time and same thread:
2018-08-18 21:16:54.145 INFO 10239 --- [pool-1-thread-1] com.test.SchedulingService : LOG FIRST
2018-08-18 21:16:54.145 INFO 10239 --- [pool-1-thread-1] com.test.SchedulingService : LOG SECOND
然后,我在两个任务上都添加了 Thread.sleep(100)
,因为我无法预测执行顺序.
Then, I added a Thread.sleep(100)
on the both tasks as I cannot predict the execution order.
2018-08-18 21:21:14.775 INFO 10274 --- [pool-1-thread-1] com.test.SchedulingService : LOG FIRST
2018-08-18 21:21:14.878 INFO 10274 --- [pool-1-thread-1] com.test.SchedulingService : LOG SECOND
日志条目之间大约有 100 毫秒的延迟,确认它们在同一线程上运行.
The delay of aprox 100ms between the log entries, confirm that they run on the same thread.
您可能认为在 @Scheduled
上设置 initialDelay = 0
可能会有所帮助,但不会;一切仍将在主线程上.
You might think that setting the initialDelay = 0
on the @Scheduled
might help, but it will not; everything will still be on the main thread.
我找到的解决方案是定义一个创建 customTaskScheduler
的自定义 bean:
The solution I found is defining a custom bean that creates a customTaskScheduler
:
@Bean()
public ThreadPoolTaskScheduler taskScheduler(){
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(2);
taskScheduler.setThreadNamePrefix("Async-");
return taskScheduler;
}
现在,日志显示两个任务同时由不同的线程执行:
Now, the logs show that both tasks are executed at the same time and by different threads:
2018-08-18 21:30:26.482 INFO 10383 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-08-18 21:30:26.486 INFO 10383 --- [ main] com.test.ProjectApplication : Started ProjectApplication in 1.767 seconds (JVM running for 2.137)
2018-08-18 21:30:26.555 INFO 10383 --- [ Async-2] com.test.SchedulingService : LOG SECOND
2018-08-18 21:30:26.555 INFO 10383 --- [ Async-1] com.test.SchedulingService : LOG FIRST
我定义了一个size = 2
的线程池.如果我有 3 个任务要运行,会发生什么?其中一个任务需要等待完成前2个的执行,释放线程并再次检查执行队列.
I defined a thread pool of size = 2
. What will happen if I have 3 tasks to run? One of the tasks will need to wait to complete the execution of the previous 2, get the thread released and check the execution queue again.
2018-08-18 21:33:48.895 INFO 10412 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-08-18 21:33:48.899 INFO 10412 --- [ main] com.test.ProjectApplication : Started ProjectApplication in 1.888 seconds (JVM running for 2.258)
2018-08-18 21:33:48.960 INFO 10412 --- [ Async-1] com.test.SchedulingService : LOG FIRST
2018-08-18 21:33:48.960 INFO 10412 --- [ Async-2] com.test.SchedulingService : LOG SECOND
2018-08-18 21:33:49.065 INFO 10412 --- [ Async-2] com.test.SchedulingService : LOG THIRD
这篇关于是什么导致 Spring 调度程序在应用程序和 servlet 启动之前执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!