是什么导致 Spring 调度程序在应用程序和 servlet 启动之前执行? [英] What causes Spring scheduler to execute before the application and servlet starts up?

查看:39
本文介绍了是什么导致 Spring 调度程序在应用程序和 servlet 启动之前执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有一些调度任务的简单 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆