diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/Scopes.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/StandardScopes.java similarity index 95% rename from org.springframework.config.java/src/main/java/org/springframework/config/java/Scopes.java rename to org.springframework.config.java/src/main/java/org/springframework/config/java/StandardScopes.java index 18782484f41..bc79b411759 100644 --- a/org.springframework.config.java/src/main/java/org/springframework/config/java/Scopes.java +++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/StandardScopes.java @@ -26,9 +26,9 @@ package org.springframework.config.java; * @author Chris Beams * @since 3.0 */ -public class Scopes { +public class StandardScopes { - private Scopes() { + private StandardScopes() { } public static final String SINGLETON = "singleton"; diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java index 4f90824c28e..720d49afbed 100644 --- a/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java +++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/ext/Bean.java @@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; 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 * singleton. */ - String scope() default Scopes.SINGLETON; + String scope() default StandardScopes.SINGLETON; /** * Bean autowire strategy. diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/AbstractConfigurationClassProcessor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/AbstractConfigurationClassProcessor.java index be58c0fb34c..a6dd7fde638 100644 --- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/AbstractConfigurationClassProcessor.java +++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/AbstractConfigurationClassProcessor.java @@ -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; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.config.java.Configuration; 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; + +/** + * Abstract superclass for processing {@link Configuration}-annotated classes and registering + * bean definitions based on {@link Bean}-annotated methods within those classes. + * + *
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}). + * + *
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 { - + /** + * 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); + /** + * 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(); + /** + * 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 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); + // return an empty registry immediately if no @Configuration classes were found 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); - return renderModelAsBeanDefinitions(configModel); - } - - 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) { + // read the model and create bean definitions based on its content return new ConfigurationModelBeanDefinitionReader().loadBeanDefinitions(configModel); } diff --git a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationPostProcessor.java b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassPostProcessor.java similarity index 88% rename from org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationPostProcessor.java rename to org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassPostProcessor.java index a5707c1f8c3..7c598cb712f 100644 --- a/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationPostProcessor.java +++ b/org.springframework.config.java/src/main/java/org/springframework/config/java/support/ConfigurationClassPostProcessor.java @@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; 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.support.BeanDefinitionRegistry; 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.MalformedConfigurationException; 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.parsing.ConfigurationParser; import org.springframework.core.Ordered; @@ -46,11 +46,23 @@ import org.springframework.util.StringUtils; /** * {@link BeanFactoryPostProcessor} used for bootstrapping processing of * {@link Configuration @Configuration} classes. + *
+ * Registered by default when using {@literal
+ * 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
- implements Ordered, BeanFactoryPostProcessor {
+public class ConfigurationClassPostProcessor extends AbstractConfigurationClassProcessor
+ 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
@@ -68,8 +80,7 @@ public class ConfigurationPostProcessor extends AbstractConfigurationClassProces
/**
- * @return the order in which this {@link BeanPostProcessor} will be executed. Returns
- * {@link Ordered#HIGHEST_PRECEDENCE}.
+ * @return {@link Ordered#HIGHEST_PRECEDENCE}.
*/
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
@@ -95,7 +106,7 @@ public class ConfigurationPostProcessor extends AbstractConfigurationClassProces
/**
* @return a ConfigurationParser that uses the enclosing BeanFactory's
- * classLoader to load all Configuration class artifacts.
+ * ClassLoader to load all Configuration class artifacts.
*/
@Override
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
protected BeanDefinitionRegistry getConfigurationBeanDefinitions(boolean includeAbstractBeanDefs) {
diff --git a/org.springframework.config.java/src/test/java/org/springframework/config/java/support/ConfigurationPostProcessorTests.java b/org.springframework.config.java/src/test/java/org/springframework/config/java/support/ConfigurationPostProcessorTests.java
index 2158e9a3834..e16f03c04e5 100644
--- a/org.springframework.config.java/src/test/java/org/springframework/config/java/support/ConfigurationPostProcessorTests.java
+++ b/org.springframework.config.java/src/test/java/org/springframework/config/java/support/ConfigurationPostProcessorTests.java
@@ -14,17 +14,17 @@ import org.springframework.config.java.ext.Bean;
import org.springframework.util.ClassUtils;
/**
- * Unit tests for {@link ConfigurationPostProcessor}
+ * Unit tests for {@link ConfigurationClassPostProcessor}
*
* @author Chris Beams
*/
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";
/**
- * 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;
* if Configuration classes are present in the bean factory and CGLIB
* is not present, an instructive exception should be thrown.
@@ -39,17 +39,17 @@ public class ConfigurationPostProcessorTests {
factory.registerBeanDefinition("config1", rootBeanDefinition(Config.class).getBeanDefinition());
- ConfigurationPostProcessor cpp = new ConfigurationPostProcessor();
+ ConfigurationClassPostProcessor cpp = new ConfigurationClassPostProcessor();
// 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 {
cpp.postProcessBeanFactory(factory);
} catch (RuntimeException ex) {
assertTrue(ex.getMessage().contains("CGLIB is required to process @Configuration classes"));
} 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.
*
* This test will fail if any CGLIB classes are classloaded before the call
- * to {@link ConfigurationPostProcessor#enhanceConfigurationClasses}
+ * to {@link ConfigurationClassPostProcessor#enhanceConfigurationClasses}
*/
@Test
public void testCglibClassesAreLoadedJustInTimeForEnhancement() throws Exception {
@@ -93,7 +93,7 @@ public class ConfigurationPostProcessorTests {
* Enhanced {@link Configuration} classes are only necessary for respecting
* 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.
* 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
@@ -104,7 +104,7 @@ public class ConfigurationPostProcessorTests {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("config",
rootBeanDefinition(SingletonBeanConfig.class).getBeanDefinition());
- new ConfigurationPostProcessor().postProcessBeanFactory(beanFactory);
+ new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
Foo foo = (Foo) beanFactory.getBean("foo");
Bar bar = (Bar) beanFactory.getBean("bar");
assertThat(foo, sameInstance(bar.foo));
diff --git a/org.springframework.config.java/src/test/java/test/basic/AutowiredConfigurationTests.xml b/org.springframework.config.java/src/test/java/test/basic/AutowiredConfigurationTests.xml
index ffdd961b422..4cb14bec881 100644
--- a/org.springframework.config.java/src/test/java/test/basic/AutowiredConfigurationTests.xml
+++ b/org.springframework.config.java/src/test/java/test/basic/AutowiredConfigurationTests.xml
@@ -7,7 +7,7 @@