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

Gan*_*alf 6 java spring tomcat spring-boot

我在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();
    }
Run Code Online (Sandbox Code Playgroud)

在我的Docker测试环境中,这很好用 - 但是当我将它部署到Tomcat 8中的Linux(Debian Jessie,Java 8)主机时,我从未看到"Starting Subscriber Thread"消息(并且线程未启动).

Mag*_*nus 12

将应用程序部署到非嵌入式应用程序服务器时,不会调用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;
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 无法在类级别添加@Bean,请参阅https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html (2认同)

Sni*_*192 5

你可以有一个实现它的bean,如果ApplicationListener<ContextRefreshedEvent>它还onApplicationEvent没有启动的话,只要启动你的线程就会被调用。顺便说一下,我想你想要 ApplicationReadyEvent 。

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

@Component
public class FooBar implements ApplicationListener<ContextRefreshedEvent> {

    Thread t = new Thread();

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (!t.isAlive()) {
            t.start();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)