introduced BeanDefinitionRegistryPostProcessor extension to BeanFactoryPostProcessor; @Configuration classes support definition of BeanFactoryPostProcessor beans as well (SPR-6455, SPR-6611)

This commit is contained in:
Juergen Hoeller
2010-01-31 14:05:28 +00:00
parent 2d6ea2f4fe
commit 6b2b5c4c23
6 changed files with 128 additions and 33 deletions

View File

@@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
@@ -48,7 +49,6 @@ import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
@@ -68,11 +68,11 @@ import org.springframework.util.StringUtils;
*/
class ConfigurationClassBeanDefinitionReader {
static final String CONFIGURATION_CLASS_FULL = "full";
private static final String CONFIGURATION_CLASS_FULL = "full";
static final String CONFIGURATION_CLASS_LITE = "lite";
private static final String CONFIGURATION_CLASS_LITE = "lite";
static final String CONFIGURATION_CLASS_ATTRIBUTE =
private static final String CONFIGURATION_CLASS_ATTRIBUTE =
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
private static final Log logger = LogFactory.getLog(ConfigurationClassBeanDefinitionReader.class);
@@ -86,7 +86,6 @@ class ConfigurationClassBeanDefinitionReader {
private final MetadataReaderFactory metadataReaderFactory;
/**
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
* to populate the given {@link BeanDefinitionRegistry}.
@@ -95,6 +94,7 @@ class ConfigurationClassBeanDefinitionReader {
*/
public ConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
ProblemReporter problemReporter, MetadataReaderFactory metadataReaderFactory) {
this.registry = registry;
this.sourceExtractor = sourceExtractor;
this.problemReporter = problemReporter;
@@ -145,13 +145,15 @@ class ConfigurationClassBeanDefinitionReader {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName));
}
} else {
}
else {
try {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
AnnotationMetadata metadata = reader.getAnnotationMetadata();
this.problemReporter.error(
new InvalidConfigurationImportProblem(className, reader.getResource(), metadata));
} catch (IOException ex) {
}
catch (IOException ex) {
throw new IllegalStateException("Could not create MetadataReader for class " + className);
}
}
@@ -181,7 +183,7 @@ class ConfigurationClassBeanDefinitionReader {
this.registry.registerAlias(beanName, alias);
}
// has this already been overriden (i.e.: via XML)?
// has this already been overridden (e.g. via XML)?
if (this.registry.containsBeanDefinition(beanName)) {
BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName);
// is the existing bean definition one that was created from a configuration class?
@@ -277,6 +279,7 @@ class ConfigurationClassBeanDefinitionReader {
}
}
/**
* Check whether the given bean definition is a candidate for a configuration class,
* and mark it accordingly.
@@ -284,7 +287,7 @@ class ConfigurationClassBeanDefinitionReader {
* @param metadataReaderFactory the current factory in use by the caller
* @return whether the candidate qualifies as (any kind of) configuration class
*/
static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
AnnotationMetadata metadata = null;
// Check already loaded Class if present...
@@ -322,6 +325,14 @@ class ConfigurationClassBeanDefinitionReader {
return false;
}
/**
* Determine whether the given bean definition indicates a full @Configuration class.
*/
public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}
/**
* {@link RootBeanDefinition} marker subclass used to signify that a bean definition
* created from a configuration class as opposed to any other configuration source.
@@ -329,7 +340,7 @@ class ConfigurationClassBeanDefinitionReader {
* definition was created externally.
*/
@SuppressWarnings("serial")
private class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
private AnnotationMetadata annotationMetadata;

View File

@@ -16,9 +16,6 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.CONFIGURATION_CLASS_ATTRIBUTE;
import static org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.CONFIGURATION_CLASS_FULL;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -40,6 +37,7 @@ import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.beans.factory.parsing.SourceExtractor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReaderFactory;
@@ -63,7 +61,7 @@ import org.springframework.util.ClassUtils;
* @author Juergen Hoeller
* @since 3.0
*/
public class ConfigurationClassPostProcessor implements BeanFactoryPostProcessor, BeanClassLoaderAware {
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, BeanClassLoaderAware {
/** Whether the CGLIB2 library is present on the classpath */
private static final boolean cglibAvailable = ClassUtils.isPresent(
@@ -124,16 +122,18 @@ public class ConfigurationClassPostProcessor implements BeanFactoryPostProcessor
}
/**
* Derive further bean definitions from the configuration classes in the registry.
*/
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
processConfigBeanDefinitions(registry);
}
/**
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
if (!(beanFactory instanceof BeanDefinitionRegistry)) {
throw new IllegalStateException(
"ConfigurationClassPostProcessor expects a BeanFactory that implements BeanDefinitionRegistry");
}
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
enhanceConfigurationClasses(beanFactory);
}
@@ -174,8 +174,8 @@ public class ConfigurationClassPostProcessor implements BeanFactoryPostProcessor
parser.validate();
// Read the model and create bean definitions based on its content
ConfigurationClassBeanDefinitionReader reader =
new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.problemReporter, this.metadataReaderFactory);
ConfigurationClassBeanDefinitionReader reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.problemReporter, this.metadataReaderFactory);
reader.loadBeanDefinitions(parser.getConfigurationClasses());
}
@@ -189,7 +189,7 @@ public class ConfigurationClassPostProcessor implements BeanFactoryPostProcessor
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<String, AbstractBeanDefinition>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
if (CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE))) {
if (ConfigurationClassBeanDefinitionReader.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@@ -39,6 +39,8 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
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.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.support.ResourceEditorRegistrar;
import org.springframework.context.ApplicationContext;
@@ -569,6 +571,21 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
* <p>Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
((BeanDefinitionRegistryPostProcessor) postProcessor).postProcessBeanDefinitionRegistry(registry);
}
}
Collection<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false).values();
for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory);