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 dda34a8b..e6999c42 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 @@ -15,15 +15,13 @@ */ package org.springframework.modulith.runtime.autoconfigure; -import java.util.concurrent.Future; -import java.util.function.Supplier; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.context.event.ApplicationStartedEvent; @@ -40,6 +38,7 @@ import org.springframework.modulith.runtime.ApplicationModulesRuntime; import org.springframework.modulith.runtime.ApplicationRuntime; import org.springframework.util.Assert; +import org.springframework.util.function.ThrowingSupplier; /** * Auto-configuration to register a {@link SpringBootApplicationRuntime}, a {@link ApplicationModulesRuntime} and an @@ -65,23 +64,25 @@ static SpringBootApplicationRuntime modulithsApplicationRuntime(ApplicationConte @ConditionalOnMissingBean static ApplicationModulesRuntime modulesRuntime(ApplicationRuntime runtime) { - var mainClass = runtime.getMainApplicationClass(); - var modules = EXECUTOR - .submit(() -> ApplicationModulesBootstrap.initializeApplicationModules(mainClass)); + ThrowingSupplier modules = () -> EXECUTOR + .submit(() -> ApplicationModulesBootstrap.initializeApplicationModules(runtime.getMainApplicationClass())) + .get(); - return new ApplicationModulesRuntime(toSupplier(modules), runtime); + return new ApplicationModulesRuntime(modules, runtime); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + @ConditionalOnBean(ApplicationModuleInitializer.class) static ApplicationListener applicationModuleInitializingListener( - ListableBeanFactory beanFactory) { + ObjectProvider runtime, + ObjectProvider initializers) { return event -> { - var modules = beanFactory.getBean(ApplicationModulesRuntime.class).get(); + var modules = runtime.getObject().get(); - beanFactory.getBeanProvider(ApplicationModuleInitializer.class).stream() // + initializers.stream() // .sorted(modules.getComparator()) // .map(it -> LOGGER.isDebugEnabled() ? new LoggingApplicationModuleInitializerAdapter(it, modules) : it) .forEach(ApplicationModuleInitializer::initialize); @@ -160,17 +161,6 @@ static ApplicationModules initializeApplicationModules(Class applicationMainC } } - private static Supplier toSupplier(Future modules) { - - return () -> { - try { - return modules.get(); - } catch (Exception o_O) { - throw new RuntimeException(o_O); - } - }; - } - /** * Auto-configuration to react to ArchUnit missing on the runtime classpath. * 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 60bd244c..8eca746a 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 @@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.modulith.ApplicationModuleInitializer; import org.springframework.modulith.runtime.ApplicationModulesRuntime; import org.springframework.modulith.runtime.ApplicationRuntime; @@ -46,11 +47,8 @@ void bootstrapRegistersRuntimeInstances() { .withUserConfiguration(SampleApp.class) .withConfiguration(AutoConfigurations.of(SpringModulithRuntimeAutoConfiguration.class)) .run(context -> { - assertThat(context.getBean(ApplicationRuntime.class)).isNotNull(); assertThat(context.getBean(ApplicationModulesRuntime.class)).isNotNull(); - - context.close(); }); } @@ -62,13 +60,25 @@ void missingArchUnitRuntimeDependencyEscalatesOnContextStartup() { .withConfiguration(AutoConfigurations.of(SpringModulithRuntimeAutoConfiguration.class)) .withClassLoader(new FilteredClassLoader(ClassFileImporter.class)) .run(context -> { - assertThat(context).hasFailed(); assertThat(context.getStartupFailure().getCause()) .isInstanceOf(BeanInstantiationException.class) .cause().isInstanceOf(MissingRuntimeDependency.class); - - context.close(); }); } + + @Test // GH-375 + void registersInitializingListenerIfInitializersPresent() { + + var beanName = "applicationModuleInitializingListener"; + var runner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SpringModulithRuntimeAutoConfiguration.class)); + + // No initializer -> no listener + runner.run(context -> assertThat(context).doesNotHaveBean(beanName)); + + // Initializer -> listener + runner.withBean(ApplicationModuleInitializer.class, () -> () -> {}) + .run(context -> assertThat(context).hasBean(beanName)); + } }