Allow default CacheAwareContextLoaderDelegate configuration via system property
Prior to this commit, the default CacheAwareContextLoaderDelegate could be configured by extending AbstractTestContextBootstrapper and overriding getCacheAwareContextLoaderDelegate(); however, this required that the user configure the custom TestContextBootstrapper via @BootstrapWith. This commit introduces a new "spring.test.context.default.CacheAwareContextLoaderDelegate" property that can be configured via a JVM system property or via the SpringProperties mechanism. BootstrapUtils uses this new property to load the default CacheAwareContextLoaderDelegate. If the property is not defined, BootstrapUtils will fall back to creating a DefaultCacheAwareContextLoaderDelegate as it did previously. This allows third parties to configure the default CacheAwareContextLoaderDelegate transparently for the user -- for example, to intercept context loading in order to load the context in a different manner -- for example, to make use of ahead of time (AOT) techniques for implementing a different type of ApplicationContext at build time. Closes gh-27540
This commit is contained in:
parent
e8f6cd10a5
commit
63fac1b7c8
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -25,9 +25,11 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.context.TestContextAnnotationUtils.AnnotationDescriptor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@code BootstrapUtils} is a collection of utility methods to assist with
|
||||
|
@ -65,7 +67,11 @@ abstract class BootstrapUtils {
|
|||
/**
|
||||
* Create the {@code BootstrapContext} for the specified {@linkplain Class test class}.
|
||||
* <p>Uses reflection to create a {@link org.springframework.test.context.support.DefaultBootstrapContext}
|
||||
* that uses a {@link org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate}.
|
||||
* that uses a default {@link CacheAwareContextLoaderDelegate} — configured
|
||||
* via the {@link CacheAwareContextLoaderDelegate#DEFAULT_CACHE_AWARE_CONTEXT_LOADER_DELEGATE_PROPERTY_NAME}
|
||||
* system property or falling back to the
|
||||
* {@link org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate}
|
||||
* if the system property is not defined.
|
||||
* @param testClass the test class for which the bootstrap context should be created
|
||||
* @return a new {@code BootstrapContext}; never {@code null}
|
||||
*/
|
||||
|
@ -90,19 +96,21 @@ abstract class BootstrapUtils {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static CacheAwareContextLoaderDelegate createCacheAwareContextLoaderDelegate() {
|
||||
Class<? extends CacheAwareContextLoaderDelegate> clazz = null;
|
||||
String className = SpringProperties.getProperty(
|
||||
CacheAwareContextLoaderDelegate.DEFAULT_CACHE_AWARE_CONTEXT_LOADER_DELEGATE_PROPERTY_NAME);
|
||||
className = (StringUtils.hasText(className) ? className.trim() :
|
||||
DEFAULT_CACHE_AWARE_CONTEXT_LOADER_DELEGATE_CLASS_NAME);
|
||||
try {
|
||||
clazz = (Class<? extends CacheAwareContextLoaderDelegate>) ClassUtils.forName(
|
||||
DEFAULT_CACHE_AWARE_CONTEXT_LOADER_DELEGATE_CLASS_NAME, BootstrapUtils.class.getClassLoader());
|
||||
|
||||
Class<? extends CacheAwareContextLoaderDelegate> clazz =
|
||||
(Class<? extends CacheAwareContextLoaderDelegate>) ClassUtils.forName(
|
||||
className, BootstrapUtils.class.getClassLoader());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Instantiating CacheAwareContextLoaderDelegate from class [%s]",
|
||||
clazz.getName()));
|
||||
logger.debug(String.format("Instantiating CacheAwareContextLoaderDelegate from class [%s]", className));
|
||||
}
|
||||
return BeanUtils.instantiateClass(clazz, CacheAwareContextLoaderDelegate.class);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Could not load CacheAwareContextLoaderDelegate [" + clazz + "]", ex);
|
||||
throw new IllegalStateException("Could not create CacheAwareContextLoaderDelegate [" + className + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -36,6 +36,20 @@ import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
|
|||
*/
|
||||
public interface CacheAwareContextLoaderDelegate {
|
||||
|
||||
/**
|
||||
* System property used to configure the fully qualified class name of the
|
||||
* default {@code CacheAwareContextLoaderDelegate}.
|
||||
* <p>May alternatively be configured via the
|
||||
* {@link org.springframework.core.SpringProperties} mechanism.
|
||||
* <p>If this property is not defined, the
|
||||
* {@link org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate
|
||||
* DefaultCacheAwareContextLoaderDelegate} will be used as the default.
|
||||
* @since 5.3.11
|
||||
*/
|
||||
String DEFAULT_CACHE_AWARE_CONTEXT_LOADER_DELEGATE_PROPERTY_NAME =
|
||||
"spring.test.context.default.CacheAwareContextLoaderDelegate";
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the {@linkplain ApplicationContext application context} for
|
||||
* the supplied {@link MergedContextConfiguration} has been loaded (i.e.,
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.support;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.test.context.CacheAwareContextLoaderDelegate;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||
|
||||
/**
|
||||
* Integration tests for configuring a custom default {@link CacheAwareContextLoaderDelegate}
|
||||
* via {@link SpringProperties}.
|
||||
*
|
||||
* @author sbrannen
|
||||
* @since 5.3.11
|
||||
*/
|
||||
class CustomDefaultCacheAwareContextLoaderDelegateTests {
|
||||
|
||||
@Test
|
||||
void customDefaultCacheAwareContextLoaderDelegateConfiguredViaSpringProperties() {
|
||||
String key = CacheAwareContextLoaderDelegate.DEFAULT_CACHE_AWARE_CONTEXT_LOADER_DELEGATE_PROPERTY_NAME;
|
||||
|
||||
try {
|
||||
SpringProperties.setProperty(key, AotCacheAwareContextLoaderDelegate.class.getName());
|
||||
|
||||
EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(TestCase.class))//
|
||||
.execute()//
|
||||
.testEvents()//
|
||||
.assertStatistics(stats -> stats.started(1).succeeded(1).failed(0));
|
||||
}
|
||||
finally {
|
||||
SpringProperties.setProperty(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class TestCase {
|
||||
|
||||
@Test
|
||||
void test(@Autowired String foo) {
|
||||
// foo will be "bar" unless the AotCacheAwareContextLoaderDelegate is registered.
|
||||
assertThat(foo).isEqualTo("AOT");
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
String foo() {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class AotCacheAwareContextLoaderDelegate extends DefaultCacheAwareContextLoaderDelegate {
|
||||
|
||||
@Override
|
||||
protected ApplicationContext loadContextInternal(MergedContextConfiguration mergedContextConfiguration) {
|
||||
GenericApplicationContext applicationContext = new GenericApplicationContext();
|
||||
applicationContext.registerBean("foo", String.class, () -> "AOT");
|
||||
applicationContext.refresh();
|
||||
return applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue