+ Renamed Scopes -> StandardScopes

+ Renamed ConfigurationPostProcessor -> ConfigurationClassPostProcessor
+ JavaDoc and polish for AbstractConfigurationClassProcessor
This commit is contained in:
Chris Beams 2009-03-06 06:55:53 +00:00
parent 8610c0bce8
commit 2e7e982487
8 changed files with 123 additions and 50 deletions

View File

@ -26,9 +26,9 @@ package org.springframework.config.java;
* @author Chris Beams * @author Chris Beams
* @since 3.0 * @since 3.0
*/ */
public class Scopes { public class StandardScopes {
private Scopes() { private StandardScopes() {
} }
public static final String SINGLETON = "singleton"; public static final String SINGLETON = "singleton";

View File

@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.config.java.Configuration; import org.springframework.config.java.Configuration;
import org.springframework.config.java.Scopes; import org.springframework.config.java.StandardScopes;
/** /**
@ -87,7 +87,7 @@ public @interface Bean {
* Scope: whether the bean is a singleton, prototype or custom scope. Default is * Scope: whether the bean is a singleton, prototype or custom scope. Default is
* singleton. * singleton.
*/ */
String scope() default Scopes.SINGLETON; String scope() default StandardScopes.SINGLETON;
/** /**
* Bean autowire strategy. * Bean autowire strategy.

View File

@ -1,47 +1,108 @@
/*
* Copyright 2002-2009 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.config.java.support; package org.springframework.config.java.support;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.config.java.Configuration;
import org.springframework.config.java.ConfigurationModel; import org.springframework.config.java.ConfigurationModel;
import org.springframework.config.java.MalformedConfigurationException;
import org.springframework.config.java.ext.Bean;
import org.springframework.config.java.internal.parsing.ConfigurationParser; import org.springframework.config.java.internal.parsing.ConfigurationParser;
/**
* Abstract superclass for processing {@link Configuration}-annotated classes and registering
* bean definitions based on {@link Bean}-annotated methods within those classes.
*
* <p>Provides template method {@link #processConfigBeanDefinitions()} that orchestrates calling each
* of several abstract methods to be overriden by concrete implementations that allow for
* customizing how {@link Configuration} classes are found ({@link #getConfigurationBeanDefinitions}),
* customizing the creation of a {@link ConfigurationParser} ({@link #createConfigurationParser}),
* and customizing {@link ConfigurationModel} validation logic ({@link #validateModel}).
*
* <p>This class was expressly designed with tooling in mind. Spring IDE will maintain it's
* own implementation of this class but still take advantage of the generic parsing algorithm
* defined here by {@link #processConfigBeanDefinitions()}.
*
* @author Chris Beams
* @since 3.0
* @see ConfigurationClassPostProcessor
*/
public abstract class AbstractConfigurationClassProcessor { public abstract class AbstractConfigurationClassProcessor {
/**
* Populate and return a registry containing all {@link Configuration} bean definitions
* to be processed.
*
* @param includeAbstractBeanDefs whether abstract Configuration bean definitions should
* be included in the resulting BeanDefinitionRegistry. Usually false, but called as true
* during the enhancement phase.
* @see #processConfigBeanDefinitions()
*/
protected abstract BeanDefinitionRegistry getConfigurationBeanDefinitions(boolean includeAbstractBeanDefs); protected abstract BeanDefinitionRegistry getConfigurationBeanDefinitions(boolean includeAbstractBeanDefs);
/**
* Create and return a new {@link ConfigurationParser}, allowing for customization of
* type (ASM/JDT/Reflection) as well as providing specialized ClassLoader during
* construction.
* @see #processConfigBeanDefinitions()
*/
protected abstract ConfigurationParser createConfigurationParser(); protected abstract ConfigurationParser createConfigurationParser();
/**
* Validate the given model and handle any errors. Implementations may choose to throw
* {@link MalformedConfigurationException}, or in the case of tooling register problems
* with the UI.
* @param configModel {@link ConfigurationModel} to validate
*/
protected abstract void validateModel(ConfigurationModel configModel); protected abstract void validateModel(ConfigurationModel configModel);
protected BeanDefinitionRegistry processConfigBeanDefinitions() { /**
* Build and validate a {@link ConfigurationModel} based on the registry of
* {@link Configuration} classes provided by {@link #getConfigurationBeanDefinitions},
* then, based on the content of that model, create and register bean definitions
* against a new {@link BeanDefinitionRegistry}, then return the registry.
*
* @return registry containing one bean definition per {@link Bean} method declared
* within the Configuration classes
*/
protected final BeanDefinitionRegistry processConfigBeanDefinitions() {
BeanDefinitionRegistry configBeanDefs = getConfigurationBeanDefinitions(false); BeanDefinitionRegistry configBeanDefs = getConfigurationBeanDefinitions(false);
// return an empty registry immediately if no @Configuration classes were found
if(configBeanDefs.getBeanDefinitionCount() == 0) if(configBeanDefs.getBeanDefinitionCount() == 0)
return configBeanDefs; // nothing to do - don't waste any more cycles return configBeanDefs;
ConfigurationModel configModel = createConfigurationModelFor(configBeanDefs); // populate a new ConfigurationModel by parsing each @Configuration classes
ConfigurationParser parser = createConfigurationParser();
for(String beanName : configBeanDefs.getBeanDefinitionNames()) {
BeanDefinition beanDef = configBeanDefs.getBeanDefinition(beanName);
String className = beanDef.getBeanClassName();
parser.parse(className, beanName);
}
ConfigurationModel configModel = parser.getConfigurationModel();
// validate the ConfigurationModel
validateModel(configModel); validateModel(configModel);
return renderModelAsBeanDefinitions(configModel); // read the model and create bean definitions based on its content
}
private ConfigurationModel createConfigurationModelFor(BeanDefinitionRegistry configBeanDefinitions) {
ConfigurationParser parser = createConfigurationParser();
for(String beanName : configBeanDefinitions.getBeanDefinitionNames()) {
BeanDefinition beanDef = configBeanDefinitions.getBeanDefinition(beanName);
String className = beanDef.getBeanClassName();
parser.parse(className, beanName);
}
return parser.getConfigurationModel();
}
private BeanDefinitionRegistry renderModelAsBeanDefinitions(ConfigurationModel configModel) {
return new ConfigurationModelBeanDefinitionReader().loadBeanDefinitions(configModel); return new ConfigurationModelBeanDefinitionReader().loadBeanDefinitions(configModel);
} }

View File

@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@ -33,6 +32,7 @@ import org.springframework.config.java.Configuration;
import org.springframework.config.java.ConfigurationModel; import org.springframework.config.java.ConfigurationModel;
import org.springframework.config.java.MalformedConfigurationException; import org.springframework.config.java.MalformedConfigurationException;
import org.springframework.config.java.UsageError; import org.springframework.config.java.UsageError;
import org.springframework.config.java.ext.Bean;
import org.springframework.config.java.internal.enhancement.ConfigurationEnhancer; import org.springframework.config.java.internal.enhancement.ConfigurationEnhancer;
import org.springframework.config.java.internal.parsing.ConfigurationParser; import org.springframework.config.java.internal.parsing.ConfigurationParser;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -46,11 +46,23 @@ import org.springframework.util.StringUtils;
/** /**
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of * {@link BeanFactoryPostProcessor} used for bootstrapping processing of
* {@link Configuration @Configuration} classes. * {@link Configuration @Configuration} classes.
* <p>
* Registered by default when using {@literal <context:annotation-config/>} or
* {@literal <context:component-scan/>}. Otherwise, may be declared manually as
* with any other BeanFactoryPostProcessor.
* <p>
* This post processor is {@link Ordered#HIGHEST_PRECEDENCE} as it's important
* that any {@link Bean} methods declared in Configuration classes have their
* respective bean definitions registered before any other BeanFactoryPostProcessor
* executes.
*
* @author Chris Beams
* @since 3.0
*/ */
public class ConfigurationPostProcessor extends AbstractConfigurationClassProcessor public class ConfigurationClassPostProcessor extends AbstractConfigurationClassProcessor
implements Ordered, BeanFactoryPostProcessor { implements Ordered, BeanFactoryPostProcessor {
private static final Log logger = LogFactory.getLog(ConfigurationPostProcessor.class); private static final Log logger = LogFactory.getLog(ConfigurationClassPostProcessor.class);
/** /**
* A well-known class in the CGLIB API used when testing to see if CGLIB * A well-known class in the CGLIB API used when testing to see if CGLIB
@ -68,8 +80,7 @@ public class ConfigurationPostProcessor extends AbstractConfigurationClassProces
/** /**
* @return the order in which this {@link BeanPostProcessor} will be executed. Returns * @return {@link Ordered#HIGHEST_PRECEDENCE}.
* {@link Ordered#HIGHEST_PRECEDENCE}.
*/ */
public int getOrder() { public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; return Ordered.HIGHEST_PRECEDENCE;
@ -95,7 +106,7 @@ public class ConfigurationPostProcessor extends AbstractConfigurationClassProces
/** /**
* @return a ConfigurationParser that uses the enclosing BeanFactory's * @return a ConfigurationParser that uses the enclosing BeanFactory's
* classLoader to load all Configuration class artifacts. * ClassLoader to load all Configuration class artifacts.
*/ */
@Override @Override
protected ConfigurationParser createConfigurationParser() { protected ConfigurationParser createConfigurationParser() {
@ -103,7 +114,8 @@ public class ConfigurationPostProcessor extends AbstractConfigurationClassProces
} }
/** /**
* @return map of all non-abstract {@link BeanDefinition}s in the enclosing {@link #beanFactory} * @return map of all non-abstract {@link BeanDefinition}s in the
* enclosing {@link #beanFactory}
*/ */
@Override @Override
protected BeanDefinitionRegistry getConfigurationBeanDefinitions(boolean includeAbstractBeanDefs) { protected BeanDefinitionRegistry getConfigurationBeanDefinitions(boolean includeAbstractBeanDefs) {

View File

@ -14,17 +14,17 @@ import org.springframework.config.java.ext.Bean;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
* Unit tests for {@link ConfigurationPostProcessor} * Unit tests for {@link ConfigurationClassPostProcessor}
* *
* @author Chris Beams * @author Chris Beams
*/ */
public class ConfigurationPostProcessorTests { public class ConfigurationPostProcessorTests {
private static final String ORIG_CGLIB_TEST_CLASS = ConfigurationPostProcessor.CGLIB_TEST_CLASS; private static final String ORIG_CGLIB_TEST_CLASS = ConfigurationClassPostProcessor.CGLIB_TEST_CLASS;
private static final String BOGUS_CGLIB_TEST_CLASS = "a.bogus.class"; private static final String BOGUS_CGLIB_TEST_CLASS = "a.bogus.class";
/** /**
* CGLIB is an optional dependency for Core Spring. If users attempt * CGLIB is an optional dependency for Spring. If users attempt
* to use {@link Configuration} classes, they'll need it on the classpath; * to use {@link Configuration} classes, they'll need it on the classpath;
* if Configuration classes are present in the bean factory and CGLIB * if Configuration classes are present in the bean factory and CGLIB
* is not present, an instructive exception should be thrown. * is not present, an instructive exception should be thrown.
@ -39,17 +39,17 @@ public class ConfigurationPostProcessorTests {
factory.registerBeanDefinition("config1", rootBeanDefinition(Config.class).getBeanDefinition()); factory.registerBeanDefinition("config1", rootBeanDefinition(Config.class).getBeanDefinition());
ConfigurationPostProcessor cpp = new ConfigurationPostProcessor(); ConfigurationClassPostProcessor cpp = new ConfigurationClassPostProcessor();
// temporarily set the cglib test class to something bogus // temporarily set the cglib test class to something bogus
ConfigurationPostProcessor.CGLIB_TEST_CLASS = BOGUS_CGLIB_TEST_CLASS; ConfigurationClassPostProcessor.CGLIB_TEST_CLASS = BOGUS_CGLIB_TEST_CLASS;
try { try {
cpp.postProcessBeanFactory(factory); cpp.postProcessBeanFactory(factory);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
assertTrue(ex.getMessage().contains("CGLIB is required to process @Configuration classes")); assertTrue(ex.getMessage().contains("CGLIB is required to process @Configuration classes"));
} finally { } finally {
ConfigurationPostProcessor.CGLIB_TEST_CLASS = ORIG_CGLIB_TEST_CLASS; ConfigurationClassPostProcessor.CGLIB_TEST_CLASS = ORIG_CGLIB_TEST_CLASS;
} }
} }
@ -59,7 +59,7 @@ public class ConfigurationPostProcessorTests {
* of {@link Configuration} classes. * of {@link Configuration} classes.
* *
* This test will fail if any CGLIB classes are classloaded before the call * This test will fail if any CGLIB classes are classloaded before the call
* to {@link ConfigurationPostProcessor#enhanceConfigurationClasses} * to {@link ConfigurationClassPostProcessor#enhanceConfigurationClasses}
*/ */
@Test @Test
public void testCglibClassesAreLoadedJustInTimeForEnhancement() throws Exception { public void testCglibClassesAreLoadedJustInTimeForEnhancement() throws Exception {
@ -93,7 +93,7 @@ public class ConfigurationPostProcessorTests {
* Enhanced {@link Configuration} classes are only necessary for respecting * Enhanced {@link Configuration} classes are only necessary for respecting
* certain bean semantics, like singleton-scoping, scoped proxies, etc. * certain bean semantics, like singleton-scoping, scoped proxies, etc.
* *
* Technically, {@link ConfigurationPostProcessor} could fail to enhance the * Technically, {@link ConfigurationClassPostProcessor} could fail to enhance the
* registered Configuration classes, and many use cases would still work. * registered Configuration classes, and many use cases would still work.
* Certain cases, however, like inter-bean singleton references would not. * Certain cases, however, like inter-bean singleton references would not.
* We test for such a case below, and in doing so prove that enhancement is * We test for such a case below, and in doing so prove that enhancement is
@ -104,7 +104,7 @@ public class ConfigurationPostProcessorTests {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("config", beanFactory.registerBeanDefinition("config",
rootBeanDefinition(SingletonBeanConfig.class).getBeanDefinition()); rootBeanDefinition(SingletonBeanConfig.class).getBeanDefinition());
new ConfigurationPostProcessor().postProcessBeanFactory(beanFactory); new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
Foo foo = (Foo) beanFactory.getBean("foo"); Foo foo = (Foo) beanFactory.getBean("foo");
Bar bar = (Bar) beanFactory.getBean("bar"); Bar bar = (Bar) beanFactory.getBean("bar");
assertThat(foo, sameInstance(bar.foo)); assertThat(foo, sameInstance(bar.foo));

View File

@ -7,7 +7,7 @@
<context:annotation-config/> <context:annotation-config/>
<bean class="org.springframework.config.java.support.ConfigurationPostProcessor"/> <bean class="org.springframework.config.java.support.ConfigurationClassPostProcessor"/>
<bean class="test.basic.AutowiredConfigurationTests$AutowiredConfig"/> <bean class="test.basic.AutowiredConfigurationTests$AutowiredConfig"/>
<bean class="test.basic.AutowiredConfigurationTests$ColorConfig"/> <bean class="test.basic.AutowiredConfigurationTests$ColorConfig"/>

View File

@ -11,9 +11,9 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.config.java.Configuration; import org.springframework.config.java.Configuration;
import org.springframework.config.java.MalformedConfigurationException; import org.springframework.config.java.MalformedConfigurationException;
import org.springframework.config.java.Scopes; import org.springframework.config.java.StandardScopes;
import org.springframework.config.java.ext.Bean; import org.springframework.config.java.ext.Bean;
import org.springframework.config.java.support.ConfigurationPostProcessor; import org.springframework.config.java.support.ConfigurationClassPostProcessor;
import test.beans.ITestBean; import test.beans.ITestBean;
import test.beans.TestBean; import test.beans.TestBean;
@ -24,7 +24,7 @@ public class BasicTests {
/** /**
* Creates a new {@link BeanFactory}, populates it with a {@link BeanDefinition} for * Creates a new {@link BeanFactory}, populates it with a {@link BeanDefinition} for
* each of the given {@link Configuration} <var>configClasses</var>, and then * each of the given {@link Configuration} <var>configClasses</var>, and then
* post-processes the factory using JavaConfig's {@link ConfigurationPostProcessor}. * post-processes the factory using JavaConfig's {@link ConfigurationClassPostProcessor}.
* When complete, the factory is ready to service requests for any {@link Bean} methods * When complete, the factory is ready to service requests for any {@link Bean} methods
* declared by <var>configClasses</var>. * declared by <var>configClasses</var>.
* *
@ -42,7 +42,7 @@ public class BasicTests {
.getBeanDefinition()); .getBeanDefinition());
} }
new ConfigurationPostProcessor().postProcessBeanFactory(factory); new ConfigurationClassPostProcessor().postProcessBeanFactory(factory);
factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor()); factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
@ -96,7 +96,7 @@ public class BasicTests {
return bar; return bar;
} }
@Bean(scope = Scopes.PROTOTYPE) @Bean(scope = StandardScopes.PROTOTYPE)
public TestBean baz() { public TestBean baz() {
return new TestBean("bar"); return new TestBean("bar");
} }

View File

@ -7,7 +7,7 @@
<context:annotation-config/> <context:annotation-config/>
<bean class="org.springframework.config.java.support.ConfigurationPostProcessor"/> <bean class="org.springframework.config.java.support.ConfigurationClassPostProcessor"/>
<bean class="test.basic.AutowiredConfigurationTests$ValueConfig"/> <bean class="test.basic.AutowiredConfigurationTests$ValueConfig"/>