From 2b6298e214b05d19f2d1ca94d345b945215956f8 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Fri, 24 Feb 2023 16:41:48 +0100 Subject: [PATCH] GH-145 - Make sure the async ApplicationModulesRuntime bootstrap doesn't prevent shutdown. We now use an AsyncTaskExecutor to bootstrap the ApplicationModules instance at startup asynchronously and - at the same time - do not block an explicit application shutdown. This also more idiomatic compared to using an ExecutorService directly. --- ...pringModulithRuntimeAutoConfiguration.java | 6 +++-- .../src/main/resources/logback.xml | 14 ++++++++++++ ...timeAutoConfigurationIntegrationTests.java | 22 +++++++++++-------- 3 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 spring-modulith-runtime/src/main/resources/logback.xml diff --git a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfiguration.java b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfiguration.java index f7706350..10f64174 100644 --- a/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfiguration.java +++ b/spring-modulith-runtime/src/main/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfiguration.java @@ -16,7 +16,6 @@ package org.springframework.modulith.runtime.autoconfigure; import java.util.List; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.function.Supplier; @@ -31,6 +30,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Role; +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.modulith.ApplicationModuleInitializer; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModules; @@ -49,6 +50,7 @@ import org.springframework.util.Assert; class SpringModulithRuntimeAutoConfiguration { private static final Logger LOGGER = LoggerFactory.getLogger(SpringModulithRuntimeAutoConfiguration.class); + private final AsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) @@ -63,7 +65,7 @@ class SpringModulithRuntimeAutoConfiguration { ApplicationModulesRuntime modulesRuntime(ApplicationRuntime runtime) { var mainClass = runtime.getMainApplicationClass(); - var modules = Executors.newFixedThreadPool(1) + var modules = executor .submit(() -> ApplicationModulesBootstrap.initializeApplicationModules(mainClass)); return new ApplicationModulesRuntime(toSupplier(modules), runtime); diff --git a/spring-modulith-runtime/src/main/resources/logback.xml b/spring-modulith-runtime/src/main/resources/logback.xml new file mode 100644 index 00000000..0f35da97 --- /dev/null +++ b/spring-modulith-runtime/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/spring-modulith-runtime/src/test/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfigurationIntegrationTests.java b/spring-modulith-runtime/src/test/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfigurationIntegrationTests.java index 54968590..e1b3537a 100644 --- a/spring-modulith-runtime/src/test/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfigurationIntegrationTests.java +++ b/spring-modulith-runtime/src/test/java/org/springframework/modulith/runtime/autoconfigure/SpringModulithRuntimeAutoConfigurationIntegrationTests.java @@ -18,30 +18,34 @@ package org.springframework.modulith.runtime.autoconfigure; import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.modulith.runtime.ApplicationModulesRuntime; import org.springframework.modulith.runtime.ApplicationRuntime; /** - * Integration thest for {@link SpringModulithRuntimeAutoConfiguration}. + * Integration test for {@link SpringModulithRuntimeAutoConfiguration}. * * @author Oliver Drotbohm */ -@SpringBootTest class SpringModulithRuntimeAutoConfigurationIntegrationTests { @SpringBootApplication static class SampleApp {} - @Autowired ApplicationContext context; - @Test // GH-87 void bootstrapRegistersRuntimeInstances() { - assertThat(context.getBean(ApplicationRuntime.class)).isNotNull(); - assertThat(context.getBean(ApplicationModulesRuntime.class)).isNotNull(); + new ApplicationContextRunner() + .withUserConfiguration(SampleApp.class) + .withConfiguration(AutoConfigurations.of(SpringModulithRuntimeAutoConfiguration.class)) + .run(context -> { + + assertThat(context.getBean(ApplicationRuntime.class)).isNotNull(); + assertThat(context.getBean(ApplicationModulesRuntime.class)).isNotNull(); + + context.close(); + }); } }