diff options
author | Emmanuel Bourg <ebourg@apache.org> | 2014-12-03 14:31:16 +0100 |
---|---|---|
committer | Emmanuel Bourg <ebourg@apache.org> | 2014-12-03 14:31:16 +0100 |
commit | c56370beb0a2bfa263e125fce107dceccee89fd3 (patch) | |
tree | 7ee611ceb0acbbdf7f83abcd72adb854b7d77225 /spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java | |
parent | aa5221b73661fa728dc4e62e1230e9104528c4eb (diff) |
Imported Upstream version 3.2.12
Diffstat (limited to 'spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java')
-rw-r--r-- | spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java new file mode 100644 index 00000000..bd84068a --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java @@ -0,0 +1,266 @@ +/* + * Copyright 2002-2013 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 + * + * http://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.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.util.StringUtils; + +/** + * Abstract, generic extension of {@link AbstractContextLoader} that loads a + * {@link GenericApplicationContext}. + * + * <ul> + * <li>If instances of concrete subclasses are invoked via the + * {@link org.springframework.test.context.ContextLoader ContextLoader} SPI, the + * context will be loaded from the <em>locations</em> provided to + * {@link #loadContext(String...)}.</li> + * <li>If instances of concrete subclasses are invoked via the + * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader} + * SPI, the context will be loaded from the {@link MergedContextConfiguration} + * provided to {@link #loadContext(MergedContextConfiguration)}. In such cases, a + * {@code SmartContextLoader} will decide whether to load the context from + * <em>locations</em> or <em>annotated classes</em>.</li> + * </ul> + * + * <p>Concrete subclasses must provide an appropriate implementation of + * {@link #createBeanDefinitionReader createBeanDefinitionReader()}, + * potentially overriding {@link #loadBeanDefinitions loadBeanDefinitions()} + * as well. + * + * @author Sam Brannen + * @author Juergen Hoeller + * @since 2.5 + * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(String...) + */ +public abstract class AbstractGenericContextLoader extends AbstractContextLoader { + + protected static final Log logger = LogFactory.getLog(AbstractGenericContextLoader.class); + + + /** + * Load a Spring ApplicationContext from the supplied {@link MergedContextConfiguration}. + * + * <p>Implementation details: + * + * <ul> + * <li>Creates a {@link GenericApplicationContext} instance.</li> + * <li>If the supplied {@code MergedContextConfiguration} references a + * {@linkplain MergedContextConfiguration#getParent() parent configuration}, + * the corresponding {@link MergedContextConfiguration#getParentApplicationContext() + * ApplicationContext} will be retrieved and + * {@linkplain GenericApplicationContext#setParent(ApplicationContext) set as the parent} + * for the context created by this method.</li> + * <li>Calls {@link #prepareContext(GenericApplicationContext)} for backwards + * compatibility with the {@link org.springframework.test.context.ContextLoader + * ContextLoader} SPI.</li> + * <li>Calls {@link #prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)} + * to allow for customizing the context before bean definitions are loaded.</li> + * <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to allow for customizing the + * context's {@code DefaultListableBeanFactory}.</li> + * <li>Delegates to {@link #loadBeanDefinitions(GenericApplicationContext, MergedContextConfiguration)} + * to populate the context from the locations or classes in the supplied + * {@code MergedContextConfiguration}.</li> + * <li>Delegates to {@link AnnotationConfigUtils} for + * {@link AnnotationConfigUtils#registerAnnotationConfigProcessors registering} + * annotation configuration processors.</li> + * <li>Calls {@link #customizeContext(GenericApplicationContext)} to allow for customizing the context + * before it is refreshed.</li> + * <li>{@link ConfigurableApplicationContext#refresh Refreshes} the + * context and registers a JVM shutdown hook for it.</li> + * </ul> + * + * @return a new application context + * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration) + * @see GenericApplicationContext + * @since 3.1 + */ + public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { + if (logger.isDebugEnabled()) { + logger.debug(String.format("Loading ApplicationContext for merged context configuration [%s].", + mergedConfig)); + } + + GenericApplicationContext context = new GenericApplicationContext(); + + ApplicationContext parent = mergedConfig.getParentApplicationContext(); + if (parent != null) { + context.setParent(parent); + } + prepareContext(context); + prepareContext(context, mergedConfig); + customizeBeanFactory(context.getDefaultListableBeanFactory()); + loadBeanDefinitions(context, mergedConfig); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + customizeContext(context); + context.refresh(); + context.registerShutdownHook(); + return context; + } + + /** + * Load a Spring ApplicationContext from the supplied {@code locations}. + * + * <p>Implementation details: + * + * <ul> + * <li>Creates a {@link GenericApplicationContext} instance.</li> + * <li>Calls {@link #prepareContext(GenericApplicationContext)} to allow for customizing the context + * before bean definitions are loaded.</li> + * <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to allow for customizing the + * context's {@code DefaultListableBeanFactory}.</li> + * <li>Delegates to {@link #createBeanDefinitionReader(GenericApplicationContext)} to create a + * {@link BeanDefinitionReader} which is then used to populate the context + * from the specified locations.</li> + * <li>Delegates to {@link AnnotationConfigUtils} for + * {@link AnnotationConfigUtils#registerAnnotationConfigProcessors registering} + * annotation configuration processors.</li> + * <li>Calls {@link #customizeContext(GenericApplicationContext)} to allow for customizing the context + * before it is refreshed.</li> + * <li>{@link ConfigurableApplicationContext#refresh Refreshes} the + * context and registers a JVM shutdown hook for it.</li> + * </ul> + * + * <p><b>Note</b>: this method does not provide a means to set active bean definition + * profiles for the loaded context. See {@link #loadContext(MergedContextConfiguration)} + * and {@link AbstractContextLoader#prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)} + * for an alternative. + * + * @return a new application context + * @see org.springframework.test.context.ContextLoader#loadContext + * @see GenericApplicationContext + * @see #loadContext(MergedContextConfiguration) + * @since 2.5 + */ + public final ConfigurableApplicationContext loadContext(String... locations) throws Exception { + if (logger.isDebugEnabled()) { + logger.debug(String.format("Loading ApplicationContext for locations [%s].", + StringUtils.arrayToCommaDelimitedString(locations))); + } + GenericApplicationContext context = new GenericApplicationContext(); + prepareContext(context); + customizeBeanFactory(context.getDefaultListableBeanFactory()); + createBeanDefinitionReader(context).loadBeanDefinitions(locations); + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + customizeContext(context); + context.refresh(); + context.registerShutdownHook(); + return context; + } + + /** + * Prepare the {@link GenericApplicationContext} created by this {@code ContextLoader}. + * Called <i>before</i> bean definitions are read. + * + * <p>The default implementation is empty. Can be overridden in subclasses to + * customize {@code GenericApplicationContext}'s standard settings. + * + * @param context the context that should be prepared + * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(String...) + * @see GenericApplicationContext#setAllowBeanDefinitionOverriding + * @see GenericApplicationContext#setResourceLoader + * @see GenericApplicationContext#setId + * @since 2.5 + */ + protected void prepareContext(GenericApplicationContext context) { + } + + /** + * Customize the internal bean factory of the ApplicationContext created by + * this {@code ContextLoader}. + * + * <p>The default implementation is empty but can be overridden in subclasses + * to customize {@code DefaultListableBeanFactory}'s standard settings. + * + * @param beanFactory the bean factory created by this {@code ContextLoader} + * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(String...) + * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding + * @see DefaultListableBeanFactory#setAllowEagerClassLoading + * @see DefaultListableBeanFactory#setAllowCircularReferences + * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping + * @since 2.5 + */ + protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { + } + + /** + * Load bean definitions into the supplied {@link GenericApplicationContext context} + * from the locations or classes in the supplied {@code MergedContextConfiguration}. + * + * <p>The default implementation delegates to the {@link BeanDefinitionReader} + * returned by {@link #createBeanDefinitionReader(GenericApplicationContext)} to + * {@link BeanDefinitionReader#loadBeanDefinitions(String) load} the + * bean definitions. + * + * <p>Subclasses must provide an appropriate implementation of + * {@link #createBeanDefinitionReader(GenericApplicationContext)}. Alternatively subclasses + * may provide a <em>no-op</em> implementation of {@code createBeanDefinitionReader()} + * and override this method to provide a custom strategy for loading or + * registering bean definitions. + * + * @param context the context into which the bean definitions should be loaded + * @param mergedConfig the merged context configuration + * @see #loadContext(MergedContextConfiguration) + * @since 3.1 + */ + protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) { + createBeanDefinitionReader(context).loadBeanDefinitions(mergedConfig.getLocations()); + } + + /** + * Factory method for creating a new {@link BeanDefinitionReader} for loading + * bean definitions into the supplied {@link GenericApplicationContext context}. + * + * @param context the context for which the {@code BeanDefinitionReader} + * should be created + * @return a {@code BeanDefinitionReader} for the supplied context + * @see #loadContext(String...) + * @see #loadBeanDefinitions + * @see BeanDefinitionReader + * @since 2.5 + */ + protected abstract BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context); + + /** + * Customize the {@link GenericApplicationContext} created by this + * {@code ContextLoader} <i>after</i> bean definitions have been + * loaded into the context but <i>before</i> the context is refreshed. + * + * <p>The default implementation is empty but can be overridden in subclasses + * to customize the application context. + * + * @param context the newly created application context + * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(String...) + * @since 2.5 + */ + protected void customizeContext(GenericApplicationContext context) { + } + +} |