如何在spring中运行@postconstruct non-blocking?

zi8p0yeb  于 2021-07-16  发布在  Java
关注(0)|答案(4)|浏览(357)
@PostConstruct
public void performStateChecks() {
   throw new RuntimeException("test");
}

如果我开始 spring 应用程序与上面的代码,它将阻止应用程序启动。
我想要的是在启动后直接执行一个方法,但是异步的。也就是说,它不应该延迟启动,也不应该阻止应用程序在失败时运行。
如何使初始化异步?

2w3kk1z5

2w3kk1z51#

我能看到的最简单的方法是使用eventlisteners和异步任务执行器。
添加此代码段可以完成以下工作:

@Component
    public class AsyncStartupRunner {

        @Bean(name = "applicationEventMulticaster")
        public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
            SimpleApplicationEventMulticaster eventMulticaster =
                    new SimpleApplicationEventMulticaster();

            eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
            return eventMulticaster;
        }

        @EventListener(ApplicationReadyEvent.class)
        public void executeAfterStartup() {
            throw new RuntimeException("Oops");
        }
    }
vdgimpew

vdgimpew2#

你可以用 EventListener 而不是 PostConstruct ,它支持 @Async :

@Service
public class MyService {    
    @Async
    @EventListener(ApplicationStartedEvent.class)
    public void performStateChecks() {
        throw new RuntimeException("test");
    }
 }

别忘了启用异步支持 @EnableAsync 注解
也可以使用其他事件,请参见 SpringApplicationEvent

hl0ma9xz

hl0ma9xz3#

有多种方法可以做到这一点。
首先,简单的单线程解决方案是创建并启动一个新线程;

@PostConstruct
public void performStateChecks() {
  new Thread(() -> { throw new RuntimeException("test"); }).start();
}

抛出的异常只会中断单独的线程,不会阻止或阻止应用程序启动。如果您对任务的结果或结果不感兴趣,这将非常有用。注意,不建议这样做,因为它在spring托管上下文之外启动单独的线程。
其次是使用executor服务并向其提交任务。spring提供了一个默认值 ThreadPoolTaskExecutor 可以用来提交任务。这将允许您访问任务的未来对象,并在以后对其进行处理;

private final ThreadPoolTaskExecutor executor;  // inject via constructor
@PostConstruct
public void performStateChecks() {
    Future<?> future = executor.submit(() -> {
      throw new RuntimeException("test");
    });
    // do something with the future later on
}

如果您对各种服务/类等有多个这样的方法和需求,那么创建一个新的asyncservice类来执行实际工作,并使用 @Async . 注入 AsyncService 通过构造函数调用所需的方法;

@EnableAsync
@Component
public class AsyncService {

    @Async
    public void doActualTest() {
      throw new RuntimeException("test");
    }
}

然后像这样使用它;

private final AsyncService asyncService; // make sure to inject this via constructor

@PostConstruct 
public void performStateChecks() {
    asyncService.doActualTest();
}
m4pnthwp

m4pnthwp4#

您可以从方法中删除@postconstruct,并让该方法成为普通方法。当applicationContext已经加载并且应用程序已经启动时,您可以手动调用它。

@SpringBootApplication
 public class ServiceLauncher {

 public static void main(String[] args) {

   ConfigurableApplicationContext context = new SpringApplication(ServiceLauncher.class).run(args);

    try {
        context.getBean(YourBean.class).performStateChecks(); // <-- this will run only after context initialization finishes
        } catch (Exception e) {
        //catch any exception here so it does not go down
        }
    }
  }
}

相关问题