java Spring Boot - 在部署时启动后台线程的最佳方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39737013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:36:05  来源:igfitidea点击:

Spring Boot - Best way to start a background thread on deployment

javaspringtomcatspring-boot

提问by Gandalf

I have a Spring Boot application deployed in Tomcat 8. When the application starts I want to start a worker Thread in the background that Spring Autowires with some dependencies. Currently I have this :

我在 Tomcat 8 中部署了一个 Spring Boot 应用程序。当应用程序启动时,我想在后台启动一个工作线程,Spring Autowires 具有一些依赖项。目前我有这个:

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan
public class MyServer extends SpringBootServletInitializer {   

    public static void main(String[] args) {
        log.info("Starting application");
        ApplicationContext ctx = SpringApplication.run(MyServer.class, args);
        Thread subscriber = new Thread(ctx.getBean(EventSubscriber.class));
        log.info("Starting Subscriber Thread");
        subscriber.start();
    }

In my Docker test environment this works just fine - but when I deploy this to my Linux (Debian Jessie, Java 8) host in Tomcat 8 I never see the "Starting Subscriber Thread" message (and the thread is not started).

在我的 Docker 测试环境中,这工作得很好 - 但是当我将它部署到 Tomcat 8 中的 Linux(Debian Jessie,Java 8)主机时,我从未看到“启动订阅者线程”消息(并且该线程未启动)。

回答by Magnus

The main method is not called when deploying the application to a non-embedded application server. The simplest way to start a thread is to do it from the beans constructor. Also a good idea to clean up the thread when the context is closed, for example:

将应用程序部署到非嵌入式应用程序服务器时,不会调用 main 方法。启动线程的最简单方法是从 beans 构造函数中进行。在上下文关闭时清理线程也是一个好主意,例如:

@Component
class EventSubscriber implements DisposableBean, Runnable {

    private Thread thread;
    private volatile boolean someCondition;

    EventSubscriber(){
        this.thread = new Thread(this);
        this.thread.start();
    }

    @Override
    public void run(){
        while(someCondition){
            doStuff();
        }
    }

    @Override
    public void destroy(){
        someCondition = false;
    }

}

回答by Snickers3192

You could have a bean which impelements ApplicationListener<ContextRefreshedEvent>It's onApplicationEventwill be called just start your thread there if it hasn't been started already. I think you want the ApplicationReadyEvent by the way.

你可以有一个 bean,ApplicationListener<ContextRefreshedEvent>onApplicationEvent会被调用,如果它尚未启动,则在那里启动你的线程。顺便说一下,我认为您想要 ApplicationReadyEvent。

EditHow to add a hook to the application context initialization event?

编辑如何向应用程序上下文初始化事件添加挂钩?

@Component
public class FooBar implements ApplicationListener<ContextRefreshedEvent> {

    Thread t = new Thread();

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (!t.isAlive()) {
            t.start();
        }
    }
}