next cut of JavaConfig metadata reading revision: using cached MetadataReaders

This commit is contained in:
Juergen Hoeller
2009-04-22 10:46:24 +00:00
parent 4c42597cbc
commit ea9d8925a2
17 changed files with 345 additions and 292 deletions

View File

@@ -192,8 +192,8 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
}
if (qualifier == null) {
Annotation targetAnnotation = null;
if (bd.getFactoryMethodForIntrospection() != null) {
targetAnnotation = bd.getFactoryMethodForIntrospection().getAnnotation(type);
if (bd.getResolvedFactoryMethod() != null) {
targetAnnotation = bd.getResolvedFactoryMethod().getAnnotation(type);
}
if (targetAnnotation == null && bd.hasBeanClass()) {
// look for matching annotation on the target class

View File

@@ -1025,7 +1025,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
if (mbd == null) {
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
mbd = new RootBeanDefinition(bd);
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.

View File

@@ -21,6 +21,7 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -43,10 +44,10 @@ import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ClassUtils;
/**
* Helper class for resolving constructors and factory methods.
@@ -247,6 +248,36 @@ class ConstructorResolver {
}
}
/**
* Resolve the factory method in the specified bean definition, if possible.
* {@link RootBeanDefinition#getResolvedFactoryMethod()} can be checked for the result.
* @param mbd the bean definition to check
*/
public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) {
Class factoryClass;
if (mbd.getFactoryBeanName() != null) {
factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName());
}
else {
factoryClass = mbd.getBeanClass();
}
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
Method uniqueCandidate = null;
for (Method candidate : candidates) {
if (mbd.isFactoryMethod(candidate)) {
if (uniqueCandidate == null) {
uniqueCandidate = candidate;
}
else if (!Arrays.equals(uniqueCandidate.getParameterTypes(), candidate.getParameterTypes())) {
uniqueCandidate = null;
break;
}
}
}
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
}
/**
* Instantiate the bean using a named factory method. The method may be static, if the
* bean definition parameter specifies a class, rather than a "factory-bean", or
@@ -306,13 +337,13 @@ class ConstructorResolver {
if (factoryMethodToUse != null) {
// Found a cached factory method...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
if (argsToUse == null && mbd.preparedConstructorArguments != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse);
}
}
}
if (factoryMethodToUse == null) {
if (factoryMethodToUse == null || argsToUse == null) {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
factoryClass = ClassUtils.getUserClass(factoryClass);
@@ -320,7 +351,8 @@ class ConstructorResolver {
List<Method> candidateSet = new ArrayList<Method>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
candidate.getName().equals(mbd.getFactoryMethodName())) {
candidate.getName().equals(mbd.getFactoryMethodName()) &&
mbd.isFactoryMethod(candidate)) {
candidateSet.add(candidate);
}
}

View File

@@ -17,9 +17,7 @@
package org.springframework.beans.factory.support;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -49,9 +47,7 @@ import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -432,31 +428,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
*/
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, DependencyDescriptor descriptor) {
resolveBeanClass(mbd, beanName);
// TODO: the following is duplicating the factory method resolution algorithm in
// ConstructorResolver quite a bit...
if (mbd.getFactoryMethodName() != null && mbd.factoryMethodForIntrospection == null) {
Class factoryClass;
if (mbd.getFactoryBeanName() != null) {
factoryClass = getType(mbd.getFactoryBeanName());
}
else {
factoryClass = mbd.getBeanClass();
}
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
Method uniqueCandidate = null;
for (Method candidate : candidates) {
if (candidate.getName().equals(mbd.getFactoryMethodName())) {
if (uniqueCandidate == null) {
uniqueCandidate = candidate;
}
else if (!Arrays.equals(uniqueCandidate.getParameterTypes(), candidate.getParameterTypes())) {
uniqueCandidate = null;
break;
}
}
}
mbd.factoryMethodForIntrospection = uniqueCandidate;
if (mbd.isFactoryMethodUnique && mbd.resolvedConstructorOrFactoryMethod == null) {
new ConstructorResolver(this, null, null, null).resolveFactoryMethodIfPossible(mbd);
}
return getAutowireCandidateResolver().isAutowireCandidate(
new BeanDefinitionHolder(mbd, beanName, getAliases(beanName)), descriptor);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* 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.
@@ -25,6 +25,7 @@ import java.util.Set;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.util.Assert;
/**
* A root bean definition represents the merged bean definition that backs
@@ -52,7 +53,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
private final Set<String> externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet<String>());
volatile Method factoryMethodForIntrospection;
boolean isFactoryMethodUnique;
/** Package-visible field for caching the resolved constructor or factory method */
volatile Object resolvedConstructorOrFactoryMethod;
@@ -198,7 +199,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param original the original bean definition to copy from
*/
public RootBeanDefinition(RootBeanDefinition original) {
super((BeanDefinition) original);
this((BeanDefinition) original);
}
/**
@@ -208,6 +209,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
*/
RootBeanDefinition(BeanDefinition original) {
super(original);
if (original instanceof RootBeanDefinition) {
this.isFactoryMethodUnique = ((RootBeanDefinition) original).isFactoryMethodUnique;
}
}
@@ -221,8 +225,26 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
}
}
public Method getFactoryMethodForIntrospection() {
return this.factoryMethodForIntrospection;
/**
* Specify a factory method name that refers to a non-overloaded method.
*/
public void setUniqueFactoryMethodName(String name) {
Assert.hasText(name, "Factory method name must not be empty");
setFactoryMethodName(name);
this.isFactoryMethodUnique = true;
}
public boolean isFactoryMethod(Method candidate) {
return (candidate != null && candidate.getName().equals(getFactoryMethodName()));
}
/**
* Return the resolved factory method as a Java Method object, if available.
* @return the factory method, or <code>null</code> if not found or not resolved yet
*/
public Method getResolvedFactoryMethod() {
Object candidate = this.resolvedConstructorOrFactoryMethod;
return (candidate instanceof Method ? (Method) candidate : null);
}
@@ -252,7 +274,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
public RootBeanDefinition cloneBeanDefinition() {
return new RootBeanDefinition(this);
}