Skip to content

Commit

Permalink
GH-375 - Avoid initialization of ApplicationModulesRuntime if possible.
Browse files Browse the repository at this point in the history
  • Loading branch information
odrotbohm committed Nov 17, 2023
1 parent 9f42ae4 commit 08e837f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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<ApplicationModules> 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<ApplicationStartedEvent> applicationModuleInitializingListener(
ListableBeanFactory beanFactory) {
ObjectProvider<ApplicationModulesRuntime> runtime,
ObjectProvider<ApplicationModuleInitializer> 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);
Expand Down Expand Up @@ -160,17 +161,6 @@ static ApplicationModules initializeApplicationModules(Class<?> applicationMainC
}
}

private static Supplier<ApplicationModules> toSupplier(Future<ApplicationModules> 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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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();
});
}

Expand All @@ -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));
}
}

0 comments on commit 08e837f

Please sign in to comment.