diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassApplicationContext.java
index 01d68da30c..ab1cd69334 100644
--- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassApplicationContext.java
+++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassApplicationContext.java
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.AbstractRefreshableApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
@@ -35,8 +36,8 @@ import org.springframework.util.StringUtils;
/**
- * Standalone application context, accepting {@link Configuration}-annotated
- * class literals as input. Useful for test harnesses or any other scenario
+ * Standalone application context, accepting {@link Configuration @Configuration}
+ * -annotated class literals as input. Useful for test harnesses or any other scenario
* where XML-based configuration is unnecessary or undesired.
*
*
In case of multiple Configuration classes, {@link Bean}
@@ -50,7 +51,8 @@ import org.springframework.util.StringUtils;
*/
public class ConfigurationClassApplicationContext extends AbstractRefreshableApplicationContext {
- private final Set> configClasses = new LinkedHashSet>();
+ private final ConfigurationClassApplicationContext.Delegate delegate =
+ new ConfigurationClassApplicationContext.Delegate();
/**
* Create a new {@link ConfigurationClassApplicationContext}, loading bean
@@ -70,7 +72,7 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
}
for (Class> configClass : configClasses) {
- addConfigurationClass(configClass);
+ this.addConfigurationClass(configClass);
}
this.refresh();
@@ -88,10 +90,7 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
* @see #refresh()
*/
public void addConfigurationClass(Class> configClass) {
- Assert.notNull(
- AnnotationUtils.findAnnotation(configClass, Configuration.class),
- "Class [" + configClass.getName() + "] is not annotated with @Configuration");
- this.configClasses.add(configClass);
+ this.delegate.addConfigurationClass(configClass);
}
/**
@@ -100,30 +99,18 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
* processors, such that {@literal @Autowired}, {@literal @Required}, and associated
* annotations can be used within Configuration classes.
*
- * Configuration class bean definitions are registered with generated bean definition names.
+ *
Configuration class bean definitions are registered with generated bean definition
+ * names unless the {@literal value} attribute is provided to the Configuration annotation.
*
* @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
* @see ConfigurationClassPostProcessor
+ * @see DefaultBeanNameGenerator
+ * @see Configuration#value()
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws IOException, BeansException {
-
- // @Autowired and friends must be enabled by default when processing @Configuration classes
- AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
-
- for (Class> configClass : configClasses) {
- AbstractBeanDefinition def = BeanDefinitionBuilder.rootBeanDefinition(configClass).getBeanDefinition();
-
- String name = AnnotationUtils.findAnnotation(configClass, Configuration.class).value();
- if (!StringUtils.hasLength(name)) {
- name = new DefaultBeanNameGenerator().generateBeanName(def, beanFactory);
- }
-
- beanFactory.registerBeanDefinition(name, def);
- }
-
- new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
+ this.delegate.loadBeanDefinitions(beanFactory);
}
/**
@@ -138,24 +125,78 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
* @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class)
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Class)
*/
- @SuppressWarnings("unchecked")
public T getBean(Class requiredType) {
- Assert.notNull(requiredType, "requiredType may not be null");
-
- Map beansOfType = this.getBeansOfType(requiredType);
-
- switch (beansOfType.size()) {
- case 0:
- throw new NoSuchBeanDefinitionException(requiredType);
- case 1:
- return (T) beansOfType.values().iterator().next();
- default:
- throw new NoSuchBeanDefinitionException(requiredType,
- beansOfType.size() + " matching bean definitions found " +
- "(" + StringUtils.collectionToCommaDelimitedString(beansOfType.keySet()) + "). " +
- "Consider qualifying with getBean(Class beanType, String beanName) or " +
- "declaring one bean definition as @Primary");
- }
+ return this.delegate.getBean(requiredType, this);
}
+
+ /**
+ * Encapsulates behavior common to {@link ConfigurationClassApplicationContext}
+ * and its {@link org.springframework.web.context.support.ConfigurationClassWebApplicationContext}
+ * variant. Both classes already participate in mutually exclusive superclass
+ * hierarchies, and this class allows for avoiding what would otherwise be a multiple
+ * inheritance problem through composition.
+ *
+ * This class is public by necessity but should be considered private and
+ * subject to change without notice.
+ */
+ public static class Delegate {
+
+ private final Set> configClasses = new LinkedHashSet>();
+
+ /**
+ * @see ConfigurationClassApplicationContext#addConfigurationClass(Class)
+ */
+ public void addConfigurationClass(Class> configClass) {
+ Assert.notNull(
+ AnnotationUtils.findAnnotation(configClass, Configuration.class),
+ "Class [" + configClass.getName() + "] is not annotated with @Configuration");
+ this.configClasses.add(configClass);
+ }
+
+ /**
+ * @see ConfigurationClassApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)
+ */
+ public void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
+ // @Autowired and friends must be enabled by default when processing @Configuration classes
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
+
+ for (Class> configClass : this.configClasses) {
+ AbstractBeanDefinition def = BeanDefinitionBuilder.rootBeanDefinition(configClass).getBeanDefinition();
+
+ String name = AnnotationUtils.findAnnotation(configClass, Configuration.class).value();
+ if (!StringUtils.hasLength(name)) {
+ name = new DefaultBeanNameGenerator().generateBeanName(def, beanFactory);
+ }
+
+ beanFactory.registerBeanDefinition(name, def);
+ }
+
+ new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
+ }
+
+ /**
+ * @see ConfigurationClassApplicationContext#getBean(Class)
+ */
+ @SuppressWarnings("unchecked")
+ public T getBean(Class requiredType, AbstractApplicationContext context) {
+ Assert.notNull(requiredType, "requiredType may not be null");
+ Assert.notNull(context, "context may not be null");
+
+ Map beansOfType = context.getBeansOfType(requiredType);
+
+ switch (beansOfType.size()) {
+ case 0:
+ throw new NoSuchBeanDefinitionException(requiredType);
+ case 1:
+ return (T) beansOfType.values().iterator().next();
+ default:
+ throw new NoSuchBeanDefinitionException(requiredType,
+ beansOfType.size() + " matching bean definitions found " +
+ "(" + StringUtils.collectionToCommaDelimitedString(beansOfType.keySet()) + "). " +
+ "Consider qualifying with getBean(Class beanType, String beanName) or " +
+ "declaring one bean definition as @Primary");
+ }
+ }
+ }
}
diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContext.java
index 866b161d7a..d3d788dda2 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContext.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContext.java
@@ -17,23 +17,14 @@
package org.springframework.web.context.support;
import java.io.IOException;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.ConfigurationClassPostProcessor;
+import org.springframework.context.annotation.ConfigurationClassApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
-import org.springframework.util.StringUtils;
/**
@@ -57,15 +48,34 @@ import org.springframework.util.StringUtils;
* to deliberately override certain bean definitions via an extra Configuration class.
*
* @author Chris Beams
- * @see org.springframework.context.annotation.ConfigurationClassApplicationContext
+ * @since 3.0
+ * @see ConfigurationClassApplicationContext
+ * @see ConfigurationClassApplicationContext.Delegate
*/
public class ConfigurationClassWebApplicationContext extends AbstractRefreshableWebApplicationContext {
+ private final ConfigurationClassApplicationContext.Delegate delegate =
+ new ConfigurationClassApplicationContext.Delegate();
+
/**
+ * Register a {@link BeanDefinition} for each {@link Configuration @Configuration}
+ * class specified by {@link #getConfigLocations()}. Enables the default set of
+ * annotation configuration post processors, such that {@literal @Autowired},
+ * {@literal @Required}, and associated annotations can be used within Configuration
+ * classes.
+ *
+ * Configuration class bean definitions are registered with generated bean
+ * definition names unless the {@literal value} attribute is provided to the
+ * Configuration annotation.
+ *
* @throws IllegalArgumentException if configLocations array is null or empty
* @throws IOException if any one configLocation is not loadable as a class
* @throws IllegalArgumentException if any one loaded class is not annotated with {@literal @Configuration}
* @see #getConfigLocations()
+ * @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
+ * @see ConfigurationClassPostProcessor
+ * @see DefaultBeanNameGenerator
+ * @see Configuration#value()
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
@@ -75,54 +85,34 @@ public class ConfigurationClassWebApplicationContext extends AbstractRefreshable
"No config locations were specified. Is the 'contextConfigLocations' " +
"context-param and/or init-param set properly in web.xml?");
- Set> configClasses = new LinkedHashSet>();
-
for (String configLocation : getConfigLocations()) {
try {
Class> configClass = ClassUtils.getDefaultClassLoader().loadClass(configLocation);
if (AnnotationUtils.findAnnotation(configClass, Configuration.class) == null) {
throw new IllegalArgumentException("Class [" + configClass.getName() + "] is not annotated with @Configuration");
}
- configClasses.add(configClass);
+ this.delegate.addConfigurationClass(configClass);
} catch (ClassNotFoundException ex) {
throw new IOException("Could not load @Configuration class [" + configLocation + "]", ex);
}
}
- // @Autowired and friends must be enabled by default when processing @Configuration classes
- AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
-
- for (Class> configClass : configClasses) {
- AbstractBeanDefinition def = BeanDefinitionBuilder.rootBeanDefinition(configClass).getBeanDefinition();
-
- String name = AnnotationUtils.findAnnotation(configClass, Configuration.class).value();
- if (!StringUtils.hasLength(name)) {
- name = new DefaultBeanNameGenerator().generateBeanName(def, beanFactory);
- }
-
- beanFactory.registerBeanDefinition(name, def);
- }
-
- new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
+ this.delegate.loadBeanDefinitions(beanFactory);
}
- @SuppressWarnings("unchecked")
+ /**
+ * Return the bean instance that matches the given object type.
+ *
+ * @param
+ * @param requiredType type the bean must match; can be an interface or superclass.
+ * {@literal null} is disallowed.
+ * @return bean matching required type
+ * @throws NoSuchBeanDefinitionException if there is not exactly one matching bean
+ * found
+ * @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class)
+ * @see org.springframework.beans.factory.BeanFactory#getBean(String, Class)
+ */
public T getBean(Class requiredType) {
- Assert.notNull(requiredType, "requiredType may not be null");
-
- Map beansOfType = this.getBeansOfType(requiredType);
-
- switch (beansOfType.size()) {
- case 0:
- throw new NoSuchBeanDefinitionException(requiredType);
- case 1:
- return (T) beansOfType.values().iterator().next();
- default:
- throw new NoSuchBeanDefinitionException(requiredType,
- beansOfType.size() + " matching bean definitions found " +
- "(" + StringUtils.collectionToCommaDelimitedString(beansOfType.keySet()) + "). " +
- "Consider qualifying with getBean(Class beanType, String beanName) or " +
- "declaring one bean definition as @Primary");
- }
+ return this.delegate.getBean(requiredType, this);
}
}