Configuration class parsing reuses metadata from AnnotatedBeanDefinition as far as possible

Issue: SPR-12394
This commit is contained in:
Juergen Hoeller
2014-10-29 22:08:48 +01:00
parent 725ad0df50
commit c7a93a80d4
3 changed files with 57 additions and 41 deletions

View File

@@ -68,11 +68,10 @@ final class ConfigurationClass {
* Create a new {@link ConfigurationClass} with the given name. * Create a new {@link ConfigurationClass} with the given name.
* @param metadataReader reader used to parse the underlying {@link Class} * @param metadataReader reader used to parse the underlying {@link Class}
* @param beanName must not be {@code null} * @param beanName must not be {@code null}
* @throws IllegalArgumentException if beanName is null (as of Spring 3.1.1)
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass) * @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/ */
public ConfigurationClass(MetadataReader metadataReader, String beanName) { public ConfigurationClass(MetadataReader metadataReader, String beanName) {
Assert.hasText(beanName, "bean name must not be null"); Assert.hasText(beanName, "Bean name must not be null");
this.metadata = metadataReader.getAnnotationMetadata(); this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource(); this.resource = metadataReader.getResource();
this.beanName = beanName; this.beanName = beanName;
@@ -96,7 +95,6 @@ final class ConfigurationClass {
* Create a new {@link ConfigurationClass} with the given name. * Create a new {@link ConfigurationClass} with the given name.
* @param clazz the underlying {@link Class} to represent * @param clazz the underlying {@link Class} to represent
* @param beanName name of the {@code @Configuration} class bean * @param beanName name of the {@code @Configuration} class bean
* @throws IllegalArgumentException if beanName is null (as of Spring 3.1.1)
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass) * @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/ */
public ConfigurationClass(Class<?> clazz, String beanName) { public ConfigurationClass(Class<?> clazz, String beanName) {
@@ -120,6 +118,19 @@ final class ConfigurationClass {
this.importedBy.add(importedBy); this.importedBy.add(importedBy);
} }
/**
* Create a new {@link ConfigurationClass} with the given name.
* @param metadata the metadata for the underlying class to represent
* @param beanName name of the {@code @Configuration} class bean
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(AnnotationMetadata metadata, String beanName) {
Assert.hasText(beanName, "Bean name must not be null");
this.metadata = metadata;
this.resource = new DescriptiveResource(metadata.getClassName());
this.beanName = beanName;
}
public AnnotationMetadata getMetadata() { public AnnotationMetadata getMetadata() {
return this.metadata; return this.metadata;

View File

@@ -41,6 +41,7 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@@ -158,7 +159,10 @@ class ConfigurationClassParser {
for (BeanDefinitionHolder holder : configCandidates) { for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition(); BeanDefinition bd = holder.getBeanDefinition();
try { try {
if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} }
else { else {
@@ -169,32 +173,26 @@ class ConfigurationClassParser {
throw ex; throw ex;
} }
catch (Exception ex) { catch (Exception ex) {
throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
} }
} }
processDeferredImportSelectors(); processDeferredImportSelectors();
} }
/**
* Parse the specified {@link Configuration @Configuration} class.
* @param className the name of the class to parse
* @param beanName may be null, but if populated represents the bean id
* (assumes that this configuration class was configured via XML)
*/
protected final void parse(String className, String beanName) throws IOException { protected final void parse(String className, String beanName) throws IOException {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className); MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName)); processConfigurationClass(new ConfigurationClass(reader, beanName));
} }
/**
* Parse the specified {@link Configuration @Configuration} class.
* @param clazz the Class to parse
* @param beanName must not be null (as of Spring 3.1.1)
*/
protected final void parse(Class<?> clazz, String beanName) throws IOException { protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName)); processConfigurationClass(new ConfigurationClass(clazz, beanName));
} }
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {

View File

@@ -23,6 +23,7 @@ import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
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.core.Conventions; import org.springframework.core.Conventions;
@@ -70,41 +71,47 @@ abstract class ConfigurationClassUtils {
* @return whether the candidate qualifies as (any kind of) configuration class * @return whether the candidate qualifies as (any kind of) configuration class
*/ */
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) { public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
AnnotationMetadata metadata = null; String className = beanDef.getBeanClassName();
if (className == null) {
return false;
}
// Check already loaded Class if present... AnnotationMetadata metadata;
// since we possibly can't even load the class file for this Class. if (beanDef instanceof AnnotatedBeanDefinition &&
if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) { className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass(); Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
metadata = new StandardAnnotationMetadata(beanClass, true); metadata = new StandardAnnotationMetadata(beanClass, true);
} }
else { else {
String className = beanDef.getBeanClassName(); try {
if (className != null) { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
try { metadata = metadataReader.getAnnotationMetadata();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className); }
metadata = metadataReader.getAnnotationMetadata(); catch (IOException ex) {
} if (logger.isDebugEnabled()) {
catch (IOException ex) { logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex);
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting factory methods: " + className, ex);
}
return false;
} }
return false;
} }
} }
if (metadata != null) { if (isFullConfigurationCandidate(metadata)) {
if (isFullConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); return true;
return true; }
} else if (isLiteConfigurationCandidate(metadata)) {
else if (isLiteConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); return true;
return true; }
} else {
return false;
} }
return false;
} }
/** /**