Polish SpringBootContextLoader

This commit is contained in:
Phillip Webb 2022-09-12 21:56:17 -07:00
parent d3957dfa3e
commit fadbb4b763

View File

@ -84,62 +84,69 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
public class SpringBootContextLoader extends AbstractContextLoader { public class SpringBootContextLoader extends AbstractContextLoader {
@Override @Override
public ApplicationContext loadContext(MergedContextConfiguration config) throws Exception { public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
Class<?>[] configClasses = config.getClasses(); assertHasClassesOrLocations(mergedConfig);
String[] configLocations = config.getLocations();
Assert.state(!ObjectUtils.isEmpty(configClasses) || !ObjectUtils.isEmpty(configLocations),
() -> "No configuration classes or locations found in @SpringApplicationConfiguration. "
+ "For default configuration detection to work you need Spring 4.0.3 or better (found "
+ SpringVersion.getVersion() + ").");
SpringApplication application = getSpringApplication(); SpringApplication application = getSpringApplication();
application.setMainApplicationClass(config.getTestClass()); application.setMainApplicationClass(mergedConfig.getTestClass());
application.addPrimarySources(Arrays.asList(configClasses)); application.addPrimarySources(Arrays.asList(mergedConfig.getClasses()));
application.getSources().addAll(Arrays.asList(configLocations)); application.getSources().addAll(Arrays.asList(mergedConfig.getLocations()));
List<ApplicationContextInitializer<?>> initializers = getInitializers(config, application); List<ApplicationContextInitializer<?>> initializers = getInitializers(mergedConfig, application);
if (config instanceof WebMergedContextConfiguration) { if (mergedConfig instanceof WebMergedContextConfiguration) {
application.setWebApplicationType(WebApplicationType.SERVLET); application.setWebApplicationType(WebApplicationType.SERVLET);
if (!isEmbeddedWebEnvironment(config)) { if (!isEmbeddedWebEnvironment(mergedConfig)) {
new WebConfigurer().configure(config, application, initializers); new WebConfigurer().configure(mergedConfig, application, initializers);
} }
} }
else if (config instanceof ReactiveWebMergedContextConfiguration) { else if (mergedConfig instanceof ReactiveWebMergedContextConfiguration) {
application.setWebApplicationType(WebApplicationType.REACTIVE); application.setWebApplicationType(WebApplicationType.REACTIVE);
} }
else { else {
application.setWebApplicationType(WebApplicationType.NONE); application.setWebApplicationType(WebApplicationType.NONE);
} }
application.setApplicationContextFactory((type) -> { application.setApplicationContextFactory((type) -> getApplicationContextFactory(mergedConfig, type));
if (type != WebApplicationType.NONE && !isEmbeddedWebEnvironment(config)) {
if (type == WebApplicationType.REACTIVE) {
return new GenericReactiveWebApplicationContext();
}
else if (type == WebApplicationType.SERVLET) {
return new GenericWebApplicationContext();
}
}
return ApplicationContextFactory.DEFAULT.create(type);
});
application.setInitializers(initializers); application.setInitializers(initializers);
ConfigurableEnvironment environment = getEnvironment(); ConfigurableEnvironment environment = getEnvironment();
if (environment != null) { if (environment != null) {
prepareEnvironment(config, application, environment, false); prepareEnvironment(mergedConfig, application, environment, false);
application.setEnvironment(environment); application.setEnvironment(environment);
} }
else { else {
application.addListeners(new PrepareEnvironmentListener(config)); application.addListeners(new PrepareEnvironmentListener(mergedConfig));
} }
String[] args = SpringBootTestArgs.get(config.getContextCustomizers()); String[] args = SpringBootTestArgs.get(mergedConfig.getContextCustomizers());
return application.run(args); return application.run(args);
} }
private void prepareEnvironment(MergedContextConfiguration config, SpringApplication application, private void assertHasClassesOrLocations(MergedContextConfiguration mergedConfig) {
boolean hasClasses = !ObjectUtils.isEmpty(mergedConfig.getClasses());
boolean hasLocations = !ObjectUtils.isEmpty(mergedConfig.getLocations());
Assert.state(hasClasses || hasLocations,
() -> "No configuration classes or locations found in @SpringApplicationConfiguration. "
+ "For default configuration detection to work you need Spring 4.0.3 or better (found "
+ SpringVersion.getVersion() + ").");
}
private ConfigurableApplicationContext getApplicationContextFactory(MergedContextConfiguration mergedConfig,
WebApplicationType type) {
if (type != WebApplicationType.NONE && !isEmbeddedWebEnvironment(mergedConfig)) {
if (type == WebApplicationType.REACTIVE) {
return new GenericReactiveWebApplicationContext();
}
if (type == WebApplicationType.SERVLET) {
return new GenericWebApplicationContext();
}
}
return ApplicationContextFactory.DEFAULT.create(type);
}
private void prepareEnvironment(MergedContextConfiguration mergedConfig, SpringApplication application,
ConfigurableEnvironment environment, boolean applicationEnvironment) { ConfigurableEnvironment environment, boolean applicationEnvironment) {
setActiveProfiles(environment, config.getActiveProfiles(), applicationEnvironment); setActiveProfiles(environment, mergedConfig.getActiveProfiles(), applicationEnvironment);
ResourceLoader resourceLoader = (application.getResourceLoader() != null) ? application.getResourceLoader() ResourceLoader resourceLoader = (application.getResourceLoader() != null) ? application.getResourceLoader()
: new DefaultResourceLoader(null); : new DefaultResourceLoader(null);
TestPropertySourceUtils.addPropertiesFilesToEnvironment(environment, resourceLoader, TestPropertySourceUtils.addPropertiesFilesToEnvironment(environment, resourceLoader,
config.getPropertySourceLocations()); mergedConfig.getPropertySourceLocations());
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, getInlinedProperties(config)); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, getInlinedProperties(mergedConfig));
} }
private void setActiveProfiles(ConfigurableEnvironment environment, String[] profiles, private void setActiveProfiles(ConfigurableEnvironment environment, String[] profiles,
@ -176,16 +183,12 @@ public class SpringBootContextLoader extends AbstractContextLoader {
return null; return null;
} }
protected String[] getInlinedProperties(MergedContextConfiguration config) { protected String[] getInlinedProperties(MergedContextConfiguration mergedConfig) {
ArrayList<String> properties = new ArrayList<>(); ArrayList<String> properties = new ArrayList<>();
// JMX bean names will clash if the same bean is used in multiple contexts // JMX bean names will clash if the same bean is used in multiple contexts
disableJmx(properties);
properties.addAll(Arrays.asList(config.getPropertySourceProperties()));
return StringUtils.toStringArray(properties);
}
private void disableJmx(List<String> properties) {
properties.add("spring.jmx.enabled=false"); properties.add("spring.jmx.enabled=false");
properties.addAll(Arrays.asList(mergedConfig.getPropertySourceProperties()));
return StringUtils.toStringArray(properties);
} }
/** /**
@ -195,31 +198,33 @@ public class SpringBootContextLoader extends AbstractContextLoader {
* initializers} and add * initializers} and add
* {@link MergedContextConfiguration#getContextInitializerClasses() initializers * {@link MergedContextConfiguration#getContextInitializerClasses() initializers
* specified on the test}. * specified on the test}.
* @param config the source context configuration * @param mergedConfig the source context configuration
* @param application the application instance * @param application the application instance
* @return the initializers to apply * @return the initializers to apply
* @since 2.0.0 * @since 2.0.0
*/ */
protected List<ApplicationContextInitializer<?>> getInitializers(MergedContextConfiguration config, protected List<ApplicationContextInitializer<?>> getInitializers(MergedContextConfiguration mergedConfig,
SpringApplication application) { SpringApplication application) {
List<ApplicationContextInitializer<?>> initializers = new ArrayList<>(); List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
for (ContextCustomizer contextCustomizer : config.getContextCustomizers()) { for (ContextCustomizer contextCustomizer : mergedConfig.getContextCustomizers()) {
initializers.add(new ContextCustomizerAdapter(contextCustomizer, config)); initializers.add(new ContextCustomizerAdapter(contextCustomizer, mergedConfig));
} }
initializers.addAll(application.getInitializers()); initializers.addAll(application.getInitializers());
for (Class<? extends ApplicationContextInitializer<?>> initializerClass : config for (Class<? extends ApplicationContextInitializer<?>> initializerClass : mergedConfig
.getContextInitializerClasses()) { .getContextInitializerClasses()) {
initializers.add(BeanUtils.instantiateClass(initializerClass)); initializers.add(BeanUtils.instantiateClass(initializerClass));
} }
if (config.getParent() != null) { if (mergedConfig.getParent() != null) {
initializers.add(new ParentContextApplicationContextInitializer(config.getParentApplicationContext())); initializers
.add(new ParentContextApplicationContextInitializer(mergedConfig.getParentApplicationContext()));
} }
return initializers; return initializers;
} }
private boolean isEmbeddedWebEnvironment(MergedContextConfiguration config) { private boolean isEmbeddedWebEnvironment(MergedContextConfiguration mergedConfig) {
return MergedAnnotations.from(config.getTestClass(), SearchStrategy.TYPE_HIERARCHY).get(SpringBootTest.class) return MergedAnnotations.from(mergedConfig.getTestClass(), SearchStrategy.TYPE_HIERARCHY)
.getValue("webEnvironment", WebEnvironment.class).orElse(WebEnvironment.NONE).isEmbedded(); .get(SpringBootTest.class).getValue("webEnvironment", WebEnvironment.class).orElse(WebEnvironment.NONE)
.isEmbedded();
} }
@Override @Override
@ -259,16 +264,16 @@ public class SpringBootContextLoader extends AbstractContextLoader {
*/ */
private static class WebConfigurer { private static class WebConfigurer {
void configure(MergedContextConfiguration configuration, SpringApplication application, void configure(MergedContextConfiguration mergedConfig, SpringApplication application,
List<ApplicationContextInitializer<?>> initializers) { List<ApplicationContextInitializer<?>> initializers) {
WebMergedContextConfiguration webConfiguration = (WebMergedContextConfiguration) configuration; WebMergedContextConfiguration webMergedConfig = (WebMergedContextConfiguration) mergedConfig;
addMockServletContext(initializers, webConfiguration); addMockServletContext(initializers, webMergedConfig);
} }
private void addMockServletContext(List<ApplicationContextInitializer<?>> initializers, private void addMockServletContext(List<ApplicationContextInitializer<?>> initializers,
WebMergedContextConfiguration webConfiguration) { WebMergedContextConfiguration webMergedConfig) {
SpringBootMockServletContext servletContext = new SpringBootMockServletContext( SpringBootMockServletContext servletContext = new SpringBootMockServletContext(
webConfiguration.getResourceBasePath()); webMergedConfig.getResourceBasePath());
initializers.add(0, new DefensiveWebApplicationContextInitializer( initializers.add(0, new DefensiveWebApplicationContextInitializer(
new ServletContextApplicationContextInitializer(servletContext, true))); new ServletContextApplicationContextInitializer(servletContext, true)));
} }
@ -308,16 +313,16 @@ public class SpringBootContextLoader extends AbstractContextLoader {
private final ContextCustomizer contextCustomizer; private final ContextCustomizer contextCustomizer;
private final MergedContextConfiguration config; private final MergedContextConfiguration mergedConfig;
ContextCustomizerAdapter(ContextCustomizer contextCustomizer, MergedContextConfiguration config) { ContextCustomizerAdapter(ContextCustomizer contextCustomizer, MergedContextConfiguration mergedConfig) {
this.contextCustomizer = contextCustomizer; this.contextCustomizer = contextCustomizer;
this.config = config; this.mergedConfig = mergedConfig;
} }
@Override @Override
public void initialize(ConfigurableApplicationContext applicationContext) { public void initialize(ConfigurableApplicationContext applicationContext) {
this.contextCustomizer.customizeContext(applicationContext, this.config); this.contextCustomizer.customizeContext(applicationContext, this.mergedConfig);
} }
} }
@ -348,10 +353,10 @@ public class SpringBootContextLoader extends AbstractContextLoader {
private class PrepareEnvironmentListener private class PrepareEnvironmentListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, PriorityOrdered { implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, PriorityOrdered {
private final MergedContextConfiguration config; private final MergedContextConfiguration mergedConfig;
PrepareEnvironmentListener(MergedContextConfiguration config) { PrepareEnvironmentListener(MergedContextConfiguration mergedConfig) {
this.config = config; this.mergedConfig = mergedConfig;
} }
@Override @Override
@ -361,7 +366,7 @@ public class SpringBootContextLoader extends AbstractContextLoader {
@Override @Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
prepareEnvironment(this.config, event.getSpringApplication(), event.getEnvironment(), true); prepareEnvironment(this.mergedConfig, event.getSpringApplication(), event.getEnvironment(), true);
} }
} }