package org.theonefx.wcframework.ioc;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.theonefx.wcframework.core.ClassWrapper;
import org.theonefx.wcframework.core.TypeConverter;
import org.theonefx.wcframework.core.exception.BeanCreationException;
import org.theonefx.wcframework.core.exception.BeanDefinitionStoreException;
import org.theonefx.wcframework.ioc.exception.TypeMismatchException;
import org.theonefx.wcframework.ioc.exception.UnsatisfiedDependencyException;
import org.theonefx.wcframework.ioc.val.ConstructorArgumentValues;
import org.theonefx.wcframework.ioc.val.ConstructorArgumentValues.ValueHolder;
import org.theonefx.wcframework.ioc.val.GenericTypeResolver;
import org.theonefx.wcframework.ioc.val.MethodParameter;
import org.theonefx.wcframework.utils.ClassUtils;
import org.theonefx.wcframework.utils.ObjectUtils;
import org.theonefx.wcframework.utils.ReflectionUtils;
import org.theonefx.wcframework.utils.StringUtils;
/**
* Class的辅助类,用于解析构造函数和工厂方法。
* 根据给定的参数匹配构造函数。
*/
class ConstructorResolver {
private final AbstractBeanFactory beanFactory;
/**
* Create a new ConstructorResolver for the given factory and instantiation strategy.
*/
public ConstructorResolver(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
/**
* "autowire constructor" (with constructor arguments by type) behavior.
* Also applied if explicit constructor argument values are specified,
* matching all remaining arguments with beans from the bean factory.
* <p>
* This corresponds to constructor injection: In this mode, a Spring bean
* factory is able to host components that expect constructor-based
* dependency resolution.
*
* @param id
* the name of the bean
* @param mbd
* the merged bean definition for the bean
* @param chosenCtors
* chosen candidate constructors (or <code>null</code> if none)
* @param explicitArgs
* argument values passed in programmatically via the getBean
* method, or <code>null</code> if none (-> use constructor
* argument values from bean definition)
* @return a BeanWrapper for the new instance
*/
public BeanWrapper autowireConstructor(final ClassWrapper<?> classWrapper, final String id, final RootBeanDefinition mbd) {
BeanWrapperImpl bw = new BeanWrapperImpl();
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// 找到一个缓存的构造函数
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(id, mbd, bw, constructorToUse, argsToResolve);
}
if (constructorToUse == null) {
// 需要确定构造函数
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(id, mbd, bw, cargs, resolvedValues);
// Take specified constructors, if any.
Constructor<?>[] candidates = null;
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = beanClass.getConstructors();
} catch (Throwable ex) {
throw new BeanCreationException(id, "Resolution of declared constructors on bean Class [" + beanClass.getName()
+ "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
for (int i = 0; i < candidates.length; i++) {
Constructor<?> candidate = candidates[i];
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy
// constructors left.
break;
}
if (paramTypes.length < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
argsHolder = createArgumentArray(id, mbd, resolvedValues, bw, paramTypes, candidate);
int typeDiffWeight = argsHolder.getTypeDifferenceWeight(paramTypes);
// Choose this constructor if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
} else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
if (constructorToUse == null) {
throw new BeanCreationException(id, "无法找到符合条件的构造函数"
+ "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
argsHolderToUse.storeCache(mbd, constructorToUse);
}
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return beanFactory.getInstantiationStrategy().instantiate(classWrapper, mbd, id, beanFactory, ctorToUse, argumentsToUse);
}
}, beanFactory.getAccessControlContext());
} else {
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(classWrapper, mbd, id, this.beanFactory, constructorToUse, argsToUse);
}
bw.setWrappedInstance(beanInstance);
return bw;
} catch (Throwable ex) {
throw new BeanCreationException(id, "Instantiation of bean failed", ex);
}
}
/**
* 使用确定名称的工厂方法创建Bean实例。
* 如果没有定义factory-bean属性但是却定义了factory-method以及class属性,那么代表着factory-method是class的一个static方法
* 否则的话肯定是使用BeanFactory中通过配置了依赖注入得来的对象的实例方法来生成目标对象。
* <p>
* 实现过程需要遍历所有与RootBeanDefinition指定的名称相同的静态方法或实例方法。
*/
public BeanWrapper instantiateUsingFactoryMethod(final ClassWrapper<?> classWrapper, final String id, final RootBeanDefinition mbd) {
BeanWrapperImpl bw = new BeanWrapperImpl();
Object factoryBean;
Class<?> factoryClass;
boolean isStatic;
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
if (factoryBeanName.equals(id)) {
throw new BeanDefinitionStoreException(id, "生成bean的工厂是自己,这是一个圈....");
}
try {
factoryBean = this.beanFactory.getBean(factoryBeanName);
} catch (BeanCreationException e) {
throw new BeanCreationException(id, "创建ID为 '" + factoryBeanName + "' 的工厂Bean时发生异常", e);
}
if (factoryBean == null) {
throw new BeanCreationException(id, "ID 为 '" + factoryBeanName + "' 的工厂Bean不存在");
}
factoryClass = factoryBean.getClass();
isStatic = false;
} else {
// 没有factoryBean定义,那么肯定是使用静态方法创建
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(id, "bean定义中既没有说明是哪个类(使用其静态方法创建),也没有说明是哪个bean工厂(使用其对象方法创建)");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(id, mbd, bw, factoryMethodToUse, argsToResolve);
}
if (factoryMethodToUse == null || argsToUse == null) {
// 寻找工厂方法
// 先找到工厂方法所在的类
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] rawCandidates;
final Class<?> factoryClazz = factoryClass;
if (System.getSecurityManager() != null) {
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
public Method[] run() {
return ReflectionUtils.getAllDeclaredMethods(factoryClazz);
}
});
} else {
rawCandidates = ReflectionUtils.getAllDeclaredMethods(factoryClazz);
}
// 找到所有可能的方法,有可能有多个
List<Method> candidateSet = new ArrayList<Method>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && candidate.getName().equals(mbd.getFactoryMethodName())) {
candidateSet.add(candidate);
}
}
Method[] candidates = candidateSet.toArray(new Method[candidateSet.size()]);
ConstructorArgumentValues resolvedValues = null;
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Method> ambiguousFactoryMethods = null;
int minNrOfArgs;
// 找到bean定义中的所有构造函数的参数(供工厂方法调用)
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(id, mbd, bw, cargs, resolvedValues);
List<Exception> causes = null;
// 遍历所有可能的方法
for (int i = 0; i < candidates.length; i++) {
Method candidate = candidates[i];
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
ArgumentsHolder argsHolder;
// Resolved constructor arguments: type conversion and/or autowiring necessary.
try {
argsHolder = createArgumentArray(id, mbd, resolvedValues, bw, paramTypes, candidate);
} catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.log.isTraceEnabled()) {
this.beanFactory.log.trace("由于异常" + ex + "导致忽bean'" + id + "'的工厂方法 [" + candidate + "]'");
}
if (i == candidates.length - 1 && argsHolderToUse == null) {
throw ex;
} else {
// 暂时不管这个异常,尝试下一个可能的方法
if (causes == null) {
causes = new LinkedList<Exception>();
}
causes.add(ex);
continue;
}
}
int typeDiffWeight = argsHolder.getTypeDifferenceWeight(paramTypes);
// 选择最匹配的方法
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
} else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<Method>();
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
if (factoryMethodToUse == null) {
boolean hasArgs = (resolvedValues.getArgumentCount() > 0);
String argDesc = "";
if (hasArgs) {
List<String> argTypes = new ArrayList<String>();
for (ValueHolder value : resolvedValues.getIndexedArgumentValues().values()) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName());
argTypes.add(argType);
}
argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
}
throw new BeanCreationException(id, "找不到合适的工厂方法: "
+ (mbd.getFactoryBeanName() != null ? "工厂Bean '" + mbd.getFactoryBeanName() + "'; " : "") + "工厂方法 '"
+ mbd.getFactoryMethodName() + "(" + argDesc + ")'. " + "请检查该方法"
+ (hasArgs ? "以及对应的参数表 " : "") + "是否存在,同时该方法还应该是一个 " + (isStatic ? "静态方法" : "非静态方法") + ".");
} else if (void.class.equals(factoryMethodToUse.getReturnType())) {
throw new BeanCreationException(id, "无效的工厂方法'" + mbd.getFactoryMethodName()
+ "': 该方法没有返回值!!!");
}
if (argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
final Object fb = factoryBean;
final Method factoryMethod = factoryMethodToUse;
final Object[] args = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return beanFactory.getInstantiationStrategy().instantiate(classWrapper, mbd, id, beanFactory, fb, factoryMethod, args);
}
}, beanFactory.getAccessControlContext());
} else {
beanInstance = beanFactory.getInstantiationStrategy().instantiate(classWrapper, mbd, id, beanFactory, factoryBean, factoryMethodToUse, argsToUse);
}
if (beanInstance == null) {
return null;
}
bw.setWrappedInstance(beanInstance);
return bw;
} catch (Throwable ex) {
throw new BeanCreationException(id, "实例化Bean失败", ex);
}
}
/**
* 解析Bean的构造函数的参数,并保存到resolvedValues对象中。
* Resolve the constructor arguments for this bean into the resolvedValues object.
*
* 这将导致查询其他的Bean。
* This may involve looking up other beans.
*
* 该方法同时也用于处理静态工厂方法
* This method is also used for handling invocations of static factory methods.
*/
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
TypeConverter converter = bw;
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
int minNrOfArgs = cargs.getArgumentCount();
for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
int index = entry.getKey();
if (index < 0) {
throw new BeanCreationException(beanName, "无效的构造函数参数索引: " + index);
}
if (index > minNrOfArgs) {
minNrOfArgs = index + 1;
}
ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
if (valueHolder.isConverted()) {
resolvedValues.addIndexedArgumentValue(index, valueHolder);
} else {
Object resolvedValue = valueResolver.resolveValueIfNecessary("构造函数的参数", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
}
for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
if (valueHolder.isConverted()) {
resolvedValues.addGenericArgumentValue(valueHolder);
} else {
Object resolvedValue = valueResolver.resolveValueIfNecessary("构造函数的参数", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
}
return minNrOfArgs;
}
/**
* Create an array of arguments to invoke a constructor or factory method,
* given the resolved constructor argument values.
*/
private ArgumentsHolder createArgumentArray(String beanName, RootBeanDefinition mbd, ConstructorArgumentValues resolvedValues, BeanWrapper bw,
Class<?>[] paramTypes, Object methodOrCtor) throws UnsatisfiedDependencyException {
String methodType = (methodOrCtor instanceof Constructor ? "构造函数" : "工厂方法");
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
// Try to find matching constructor argument value, either indexed
// or generic.
ConstructorArgumentValues.ValueHolder valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, usedValueHolders);
// If we couldn't find a direct match and are not supposed to
// autowire,
// let's try the next generic, untyped argument value as fallback:
// it could match after type conversion (for example, String ->
// int).
if (valueHolder == null) {
valueHolder = resolvedValues.getGenericArgumentValue(null, usedValueHolders);
}
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
usedValueHolders.add(valueHolder);
Object originalValue = valueHolder.getValue();
Object convertedValue;
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
} else {
ConstructorArgumentValues.ValueHolder sourceHolder = (ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
Object sourceValue = sourceHolder.getValue();
try {
convertedValue = bw.convertIfNecessary(originalValue, paramType, MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
// }
} catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(beanName, paramIndex, paramType,
"无法将请求的参数 [" + ObjectUtils.nullSafeClassName(valueHolder.getValue()) + "] " +
"转换为 " + methodType +
"需要的参数类型[" + paramType.getName() + "]: " + ex.getMessage());
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
for (String autowiredBeanName : autowiredBeanNames) {
if (this.beanFactory.log.isDebugEnabled()) {
this.beanFactory.log.debug("Autowiring by type from bean name '" + beanName + "' via " + methodType + " to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
/**
* 将参数转换为member需要的类型
*/
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
Class<?>[] paramTypes = (methodOrCtor instanceof Method ? ((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes());
TypeConverter converter = bw;
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
Object[] resolvedArgs = new Object[argsToResolve.length];
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
Object argValue = argsToResolve[argIndex];
MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, argIndex);
GenericTypeResolver.resolveParameterType(methodParam, methodOrCtor.getDeclaringClass());
if (argValue instanceof BeanMetadataElement) {
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
}
Class<?> paramType = paramTypes[argIndex];
try {
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
} catch (TypeMismatchException ex) {
String methodType = (methodOrCtor instanceof Constructor ? "构造函数" : "工厂方法");
throw new UnsatisfiedDependencyException(beanName, argIndex, paramType, "无法将给定的参数[" + ObjectUtils.nullSafeClassName(argValue) + "]转换为"
+ methodType + " 需要的参数类型 [" + paramType.getName() + "]: " + ex.getMessage());
}
}
return resolvedArgs;
}
/**
* 内部类,用于保存参数组合
*/
private static class ArgumentsHolder {
public final Object rawArguments[];
public final Object arguments[];
public final Object preparedArguments[];
public boolean resolveNecessary = false;
public ArgumentsHolder(int size) {
this.rawArguments = new Object[size];
this.arguments = new Object[size];
this.preparedArguments = new Object[size];
}
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
// If valid arguments found, determine type difference weight.
// Try type difference weight on both the converted arguments and
// the raw arguments. If the raw weight is better, use it.
// Decrease raw weight by 1024 to prefer it over equal converted
// weight.
int typeDiffWeight = getTypeDifferenceWeight(paramTypes, this.arguments);
int rawTypeDiffWeight = getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight);
}
public void storeCache(RootBeanDefinition mbd, Object constructorOrFactoryMethod) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
mbd.constructorArgumentsResolved = true;
if (this.resolveNecessary) {
mbd.preparedConstructorArguments = this.preparedArguments;
} else {
mbd.resolvedConstructorArguments = this.arguments;
}
}
}
/**
* Algorithm that judges the match between the declared parameter types of a candidate method
* and a specific list of arguments that this method is supposed to be invoked with.
* <p>Determines a weight that represents the class hierarchy difference between types and
* arguments. A direct match, i.e. type Integer -> arg of class Integer, does not increase
* the result - all direct matches means weight 0. A match between type Object and arg of
* class Integer would increase the weight by 2, due to the superclass 2 steps up in the
* hierarchy (i.e. Object) being the last one that still matches the required type Object.
* Type Number and class Integer would increase the weight by 1 accordingly, due to the
* superclass 1 step up the hierarchy (i.e. Number) still matching the required type Number.
* Therefore, with an arg of type Integer, a constructor (Integer) would be preferred to a
* constructor (Number) which would in turn be preferred to a constructor (Object).
* All argument weights get accumulated.
* @param paramTypes the parameter types to match
* @param args the arguments to match
* @return the accumulated weight for all arguments
*/
public static int getTypeDifferenceWeight(Class<?>[] paramTypes, Object[] args) { int result = 0;
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) {
return Integer.MAX_VALUE;
}
if (args[i] != null) {
Class<?> paramType = paramTypes[i];
Class<?> superClass = args[i].getClass().getSuperclass();
while (superClass != null) {
if (paramType.equals(superClass)) {
result = result + 2;
superClass = null;
}
else if (ClassUtils.isAssignable(paramType, superClass)) {
result = result + 2;
superClass = superClass.getSuperclass();
}
else {
superClass = null;
}
}
if (paramType.isInterface()) {
result = result + 1;
}
}
}
return result;
}
}
}