@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -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;
@@ -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 .
*
* < p > In case of multiple Configuration classes , { @link Bean }
@ -50,7 +51,8 @@ import org.springframework.util.StringUtils;
@@ -50,7 +51,8 @@ import org.springframework.util.StringUtils;
* /
public class ConfigurationClassApplicationContext extends AbstractRefreshableApplicationContext {
private final Set < Class < ? > > configClasses = new LinkedHashSet < Class < ? > > ( ) ;
private final ConfigurationClassApplicationContext . Delegate delegate =
new ConfigurationClassApplicationContext . Delegate ( ) ;
/ * *
* Create a new { @link ConfigurationClassApplicationContext } , loading bean
@ -70,7 +72,7 @@ public class ConfigurationClassApplicationContext extends AbstractRefreshableApp
@@ -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
@@ -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
@@ -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 .
*
* < p > Configuration class bean definitions are registered with generated bean definition names .
* < p > 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
@@ -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 > T getBean ( Class < T > requiredType ) {
Assert . notNull ( requiredType , "requiredType may not be null" ) ;
Map < String , ? > 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<T> 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 .
*
* < p > < strong > This class is public by necessity but should be considered private and
* subject to change without notice . < / strong >
* /
public static class Delegate {
private final Set < Class < ? > > configClasses = new LinkedHashSet < Class < ? > > ( ) ;
/ * *
* @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 > T getBean ( Class < T > requiredType , AbstractApplicationContext context ) {
Assert . notNull ( requiredType , "requiredType may not be null" ) ;
Assert . notNull ( context , "context may not be null" ) ;
Map < String , ? > 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<T> beanType, String beanName) or " +
"declaring one bean definition as @Primary" ) ;
}
}
}
}