Java 如何在春季运行@PostConstruct non-blocking?
如果我用上面的代码启动Java 如何在春季运行@PostConstruct non-blocking?,java,spring,spring-boot,spring-async,Java,Spring,Spring Boot,Spring Async,如果我用上面的代码启动spring应用程序,它将阻止应用程序启动 我想要的是在启动后直接执行一个方法,但是异步执行。也就是说,它不应该延迟启动,也不应该阻止应用程序在出现故障时运行 如何使初始化异步?您可以从方法中删除@PostConstruct,并让该方法成为普通方法。然后,当ApplicationContext已经加载并且应用程序已经启动时,您可以手动调用它 @PostConstruct public void performStateChecks() { throw new Runt
spring
应用程序,它将阻止应用程序启动
我想要的是在启动后直接执行一个方法,但是异步执行。也就是说,它不应该延迟启动,也不应该阻止应用程序在出现故障时运行
如何使初始化异步?您可以从方法中删除@PostConstruct,并让该方法成为普通方法。然后,当ApplicationContext已经加载并且应用程序已经启动时,您可以手动调用它
@PostConstruct
public void performStateChecks() {
throw new RuntimeException("test");
}
@springboot应用程序
公共类ServiceLauncher{
公共静态void main(字符串[]args){
ConfigurableApplicationContext上下文=新的SpringApplication(ServiceLauncher.class).run(args);
试一试{
context.getBean(YourBean.class).performStateChecks();//您可以从方法中删除@PostConstruct,并让该方法成为普通方法。然后,您可以在ApplicationContext已加载且应用程序已启动时手动调用它
@PostConstruct
public void performStateChecks() {
throw new RuntimeException("test");
}
@springboot应用程序
公共类ServiceLauncher{
公共静态void main(字符串[]args){
ConfigurableApplicationContext上下文=新的SpringApplication(ServiceLauncher.class).run(args);
试一试{
context.getBean(YourBean.class).performStateChecks();//有多种方法可以做到这一点
首先,简单的单线程解决方案是创建并启动一个新线程
@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
}
}
}
}
抛出的异常只会中断单独的线程,不会阻止或阻止应用程序启动。如果您对任务的结果或结果不感兴趣,这将非常有用。请注意,不建议这样做,因为它会在spring托管上下文之外启动单独的线程
其次是使用executor服务并向其提交任务。Spring提供了一个默认的ThreadPoolTaskExecutor
,可用于提交任务。这将允许您访问任务的未来对象,并在以后对其进行处理
@PostConstruct
public void performStateChecks() {
new Thread(() -> { throw new RuntimeException("test"); }).start();
}
然后像这样使用它
@EnableAsync
@Component
public class AsyncService {
@Async
public void doActualTest() {
throw new RuntimeException("test");
}
}
有多种方法可以做到这一点
首先,简单的单线程解决方案是创建并启动一个新线程
@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
}
}
}
}
抛出的异常只会中断单独的线程,不会阻止或阻止应用程序启动。如果您对任务的结果或结果不感兴趣,这将非常有用。请注意,不建议这样做,因为它会在spring托管上下文之外启动单独的线程
其次是使用executor服务并向其提交任务。Spring提供了一个默认的ThreadPoolTaskExecutor
,可用于提交任务。这将允许您访问任务的未来对象,并在以后对其进行处理
@PostConstruct
public void performStateChecks() {
new Thread(() -> { throw new RuntimeException("test"); }).start();
}
然后像这样使用它
@EnableAsync
@Component
public class AsyncService {
@Async
public void doActualTest() {
throw new RuntimeException("test");
}
}
我能看到的最简单的方法是使用EventListeners和异步任务执行器
添加此代码段将完成以下工作:
private final AsyncService asyncService; // make sure to inject this via constructor
@PostConstruct
public void performStateChecks() {
asyncService.doActualTest();
}
我能看到的最简单的方法是使用EventListeners和异步任务执行器
添加此代码段将完成以下工作:
private final AsyncService asyncService; // make sure to inject this via constructor
@PostConstruct
public void performStateChecks() {
asyncService.doActualTest();
}
您可以使用EventListener
而不是PostConstruct
,它支持@Async
:
@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");
}
}
不要忘记通过@EnableAsync
注释启用异步支持
您还可以使用一些其他事件,请参见SpringApplicationEvent
类的继承者您可以使用EventListener
而不是PostConstruct
,它支持@Async
:
@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");
}
}
不要忘记通过@EnableAsync
注释启用异步支持
您还可以使用一些其他事件,请参见SpringApplicationEvent
类的继承者使用@Async
?或者只使用一个简单的TaskExecutor
?@Async
@PostConstruct
不是异步执行的。因此,如果这是唯一的机会,我当然可以从PostConstruct中调用另一个异步bean。不要使用<代码>@PostConstruct
。它作为应用程序初始化/启动的一部分执行,错误将停止(正如您所注意到的)。因此,不要使用@PostConstruct
,也不要在该方法中使用适当的异常处理。但您可能最好使用事件侦听器来初始化某些内容。使用@Async
?或者只使用一个简单的任务执行器@Async
@PostConstruct
不是异步执行的。因此我当然可以调用postconstruct中的另一个异步bean,如果这是唯一的机会的话。不要为此使用@postconstruct
。它是作为应用程序初始化/启动的一部分执行的,错误将停止(正如您所注意到的)。因此,不要为此使用@PostConstruct
,也不要在该方法中使用适当的异常处理。但您可能最好使用事件侦听器来初始化某些内容。我不会调用前两个解决方案,因为它们将启动自己的线程。您应该委托给@Async
方法(作为第三个解决方案)或者注入一个托管线程池来启动线程。您不应该自己启动线程。您不应该启动自己的线程,而且创建一个非共享执行器服务看起来就像一个代码smell@M.Deinum谢谢,我同意你的意见。更新了答案。我不会把前两个解决方案称为“解决方案”,因为这两个解决方案将开始使用n个线程。您应该委托给@Async
方法(作为第三个解决方案)或者注入一个托管线程池来启动线程。您不应该自己启动线程。您不应该启动自己的线程,而且创建一个非共享执行器服务看起来就像一个代码smell@M.Deinum谢谢,同意你的评论。更新了答案我不太喜欢这个解决方案,因为它直接放在里面主方法我不太喜欢这个解决方案,因为它直接放在主方法中