当前位置: 首页> 教育> 锐评 > 变态魔域游戏_appmaker制作app教程_企业网站推广的形式有_百度代理授权查询

变态魔域游戏_appmaker制作app教程_企业网站推广的形式有_百度代理授权查询

时间:2025/7/11 11:51:26来源:https://blog.csdn.net/zlk252620068/article/details/145516582 浏览次数:0次
变态魔域游戏_appmaker制作app教程_企业网站推广的形式有_百度代理授权查询

在 spring 中,对象的实例化创建都在 AbstractAutowireCapableBeanFactory#createBeanInstance 方法中完成,其中定义了不少实例化策略,如:Supplier、工厂方法、构造方法、无参构造。其中无参构造,即 AbstractAutowireCapableBeanFactory#instantiateBean 最为常用,但还有一种在框架整合中也挺常用,就是我们今天要介绍的基于构造方法的对象创建。

// 通过构造方法实例化实例
// AbstractAutowireCapableBeanFactory
protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {// 此处 this 即 BeanFactoryreturn new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

传入 BeanFactory,封装一个 ConstructorResolver,之后调用 autowireConstructor 方法。

// ConstructorResolver
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {BeanWrapperImpl bw = new BeanWrapperImpl();// 设置类型转换this.beanFactory.initBeanWrapper(bw);Constructor<?> constructorToUse = null;ArgumentsHolder argsHolderToUse = null;Object[] argsToUse = null;if (explicitArgs != null) {argsToUse = explicitArgs;}else {Object[] argsToResolve = null;synchronized (mbd.constructorArgumentLock) {constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;if (constructorToUse != null && mbd.constructorArgumentsResolved) {// Found a cached constructor...// 之前处理过,所以 mbd 中相关参数已赋值argsToUse = mbd.resolvedConstructorArguments;if (argsToUse == null) {argsToResolve = mbd.preparedConstructorArguments;}}}if (argsToResolve != null) {argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);}}if (constructorToUse == null || argsToUse == null) {// Take specified constructors, if any.Constructor<?>[] candidates = chosenCtors;if (candidates == null) {Class<?> beanClass = mbd.getBeanClass();try {// mbd.isNonPublicAccessAllowed() 默认 true,即只获取自己定义的构造方法candidates = (mbd.isNonPublicAccessAllowed() ?beanClass.getDeclaredConstructors() : beanClass.getConstructors());}catch (Throwable ex) {throw ...}}// 候选只有一个,显式参数为 null,且 mbd 中不存在 constructorArgumentValuesif (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {Constructor<?> uniqueCandidate = candidates[0];if (uniqueCandidate.getParameterCount() == 0) {synchronized (mbd.constructorArgumentLock) {mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;mbd.constructorArgumentsResolved = true;mbd.resolvedConstructorArguments = EMPTY_ARGS;}bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));return bw;}}// Need to resolve the constructor.boolean autowiring = (chosenCtors != null ||mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);ConstructorArgumentValues resolvedValues = null;int minNrOfArgs;// 存在显式参数 if (explicitArgs != null) {minNrOfArgs = explicitArgs.length;}else {// 获取封装的构造参数ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();resolvedValues = new ConstructorArgumentValues();// 解析构造参数,解析 cargs,填充 resolvedValuesminNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}// 按参数数量对候选的构造方法排序AutowireUtils.sortConstructors(candidates);int minTypeDiffWeight = Integer.MAX_VALUE;Set<Constructor<?>> ambiguousConstructors = null;Deque<UnsatisfiedDependencyException> causes = null;// 遍历定义的构造方法集合for (Constructor<?> candidate : candidates) {int parameterCount = candidate.getParameterCount();// 已经找到满意的构造方法,退出循环if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {break;}// 构造方法参数数量 小于 给定参数最小数量,不匹配,找下一个if (parameterCount < minNrOfArgs) {continue;}ArgumentsHolder argsHolder;Class<?>[] paramTypes = candidate.getParameterTypes();if (resolvedValues != null) {try {// 是否持有 @ConstructorProperties 注解,获取参数名称String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);if (paramNames == null) {// 不存在,通过 ASM 获取候选构造方法参数名称数组ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();if (pnd != null) {paramNames = pnd.getParameterNames(candidate);}}// 创建参数数组argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);}catch (UnsatisfiedDependencyException ex) {if (logger.isTraceEnabled()) {logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);}// Swallow and try next constructor.if (causes == null) {causes = new ArrayDeque<>(1);}causes.add(ex);continue;}}else {// Explicit arguments given -> arguments length must match exactly.if (parameterCount != explicitArgs.length) {continue;}argsHolder = new ArgumentsHolder(explicitArgs);}// mbd.isLenientConstructorResolution() 默认返回 trueint typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));// Choose this constructor if it represents the closest match.// 选择类型差异最小的,表明最接近if (typeDiffWeight < minTypeDiffWeight) {constructorToUse = candidate;argsHolderToUse = argsHolder;argsToUse = argsHolder.arguments;minTypeDiffWeight = typeDiffWeight;ambiguousConstructors = null;}// minTypeDiffWeight 初始值 Integer.MAX_VALUE,而执行 argsHolder.getTypeDifferenceWeight(paramTypes) 时类型不匹配也返回 Integer.MAX_VALUE// 此时认为这个构造方法模糊不清  else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {if (ambiguousConstructors == null) {ambiguousConstructors = new LinkedHashSet<>();ambiguousConstructors.add(constructorToUse);}ambiguousConstructors.add(candidate);}}// 没找到可用的构造方法,抛出异常if (constructorToUse == null) {if (causes != null) {UnsatisfiedDependencyException ex = causes.removeLast();for (Exception cause : causes) {this.beanFactory.onSuppressedException(cause);}throw ex;}throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Could not resolve matching constructor on bean class [" + mbd.getBeanClassName() + "] " +"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");}// 找到了可用的,但存在模糊的,isLenientConstructorResolution() 返回 true,所以也不会抛出异常else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Ambiguous constructor matches found on bean class [" + mbd.getBeanClassName() + "] " +"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +ambiguousConstructors);}if (explicitArgs == null && argsHolderToUse != null) {// mbd 中相关属性赋值,下一次又创建相同的对象时,可以快速获取要使用的构造方法和参数argsHolderToUse.storeCache(mbd, constructorToUse);}}Assert.state(argsToUse != null, "Unresolved constructor arguments");// 确定了构造方法和参数,实例化对象,将实例对象设置给 bwbw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));return bw;
}

代码有点长,核心逻辑如下:

  1. 创建一个 BeanWrapperImpl,并进行初始化,其实就是设置类型转换策略
  2. 不存在显式参数,查看 mbd 中相关字段是否已赋值,如果已经赋值,表明这个 mbd 在之前被解析过,可快速获取可用构造方法和参数值,继而完成对象的实例化
  3. mbd 在之前未解析过,获取 constructorToUse 为 null,此时,开始真正的处理。先获取 beanClass 中所有自己定义的构造方法,此处有一特例,就是构造方法只有一个,又不存在显式参数,并且 mbd 中不存在 constructorArgumentValues,这样将参数赋值为 EMPTY_ARGS,直接进行实例化。
  4. 非特例,获取 mbd 中 constructorArgumentValues,对其进行解析,如果是依赖的未创建的对象,会在此时进行创建,之后填充一个新的 ConstructorArgumentValues,称之为 resolvedValues
  5. 对所有的构造方法集合按参数数量进行排序
  6. 遍历构造方法集合,候选的构造方法参数数量小于给定的参数数量认为不匹配,接着通过 ASM 获取构造方法参数名称,之后创建参数数组,命名为 argsHolder
  7. 解析完参数之后,与构造方法参数类型进行比较,此处定义了一个 typeDiffWeight,类型差异权重,选取差异最小的,作为 constructorToUse
  8. 如果没找到相匹配的构造方法,抛出异常
  9. 找到了 constructorToUse,为 mbd 中相关属性赋值,下一次又创建相同的对象时,可以快速获取要使用的构造方法和参数
  10. 确定了构造方法和参数,实例化对象,将实例对象设置给 bw 返回

在上面的核心逻辑中,主要关注三点:构造参数的解析、创建参数数组、类型差异权重筛选出构造方法。下面分别来介绍。

构造参数的解析

// 解析构造方法参数,对依赖的参数对象,未创建的此时进行创建,之后重新封装 ConstructorArgumentValues
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();TypeConverter converter = (customConverter != null ? customConverter : bw);// 封装一个 BeanDefinitionValueResolverBeanDefinitionValueResolver valueResolver =new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);// 最小参数数量int minNrOfArgs = cargs.getArgumentCount();// 遍历给定参数,对每一个执行解析// indexedArgumentValues 是一个 Mapfor (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {int index = entry.getKey();if (index < 0) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Invalid constructor argument index: " + index);}// 根据索引修正最小参数长度,比如指定了3个,实际有四个,其中一个可以为 nullif (index + 1 > minNrOfArgs) {minNrOfArgs = index + 1;}ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();if (valueHolder.isConverted()) {resolvedValues.addIndexedArgumentValue(index, valueHolder);}else {Object resolvedValue =valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());ConstructorArgumentValues.ValueHolder resolvedValueHolder =new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());resolvedValueHolder.setSource(valueHolder);resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);}}// genericArgumentValues 是一个 Listfor (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {if (valueHolder.isConverted()) {resolvedValues.addGenericArgumentValue(valueHolder);}else {Object resolvedValue =valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());resolvedValueHolder.setSource(valueHolder);resolvedValues.addGenericArgumentValue(resolvedValueHolder);}}return minNrOfArgs;
}

 通过定义的 BeanDefinitionValueResolver,对封装 BeanDefinition 时添加的构造参数进行解析。构造方法对依赖的参数对象,如果没有创建,则在此时完成创建。

ConstructorArgumentValues,这是构造方法参数值的容器,通常作为bean定义的一部分。支持构造函数参数列表中指定索引的值以及按类型匹配的泛型参数,分别对应两个字段,indexedArgumentValues 和 genericArgumentValues。indexedArgumentValues 是一个 Map,key 为参数索引,value 为参数值;genericArgumentValues 是一个 List。indexedArgumentValues 和 genericArgumentValues 在 BeanDefinition 定义时可以同时设置,也可以只设置其中的某一个。

执行完 resolveConstructorArguments,只是对给定的参数进行了解析创建,并不确定应用给哪一个构造方法。接着来看第二点,创建参数数组。

创建参数数组

解析完参数之后,就需要确定相应的构造方法了,此时对 beanClass 中自定义的构造方法进行遍历。给定的参数,未必就是构造方法需要的类型,所以需要进行校验和转换。

private ArgumentsHolder createArgumentArray(String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();// 类型转换器 bwTypeConverter converter = (customConverter != null ? customConverter : bw);ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);Set<String> autowiredBeanNames = new LinkedHashSet<>(4);for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {Class<?> paramType = paramTypes[paramIndex];// 根据索引获取参数名称String paramName = (paramNames != null ? paramNames[paramIndex] : "");// Try to find matching constructor argument value, either indexed or generic.ConstructorArgumentValues.ValueHolder valueHolder = null;if (resolvedValues != null) {// 得到 valueHoldervalueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, 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).// valueHolder 未找到,从 genericArgumentValues 中再查找一次,这次 类型 和 名称 都为 nullif (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);}}if (valueHolder != null) {// 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 {// 方法参数,executable 指定方法,paramIndex 指定方法参数索引// 表示 executable 中第 paramIndex 个参数MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);try {// 类型转换convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);}catch (TypeMismatchException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),"Could not convert argument value of type [" +ObjectUtils.nullSafeClassName(valueHolder.getValue()) +"] to required type [" + paramType.getName() + "]: " + ex.getMessage());}Object sourceHolder = valueHolder.getSource();if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();args.resolveNecessary = true;args.preparedArguments[paramIndex] = sourceValue;}}// 参数数组,后续使用args.arguments[paramIndex] = convertedValue;args.rawArguments[paramIndex] = originalValue;}else {MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);// No explicit match found: we're either supposed to autowire or// have to fail creating an argument array for the given constructor.if (!autowiring) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),"Ambiguous argument values for parameter of type [" + paramType.getName() +"] - did you specify the correct bean references as arguments?");}try {Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);args.rawArguments[paramIndex] = autowiredArgument;args.arguments[paramIndex] = autowiredArgument;args.preparedArguments[paramIndex] = autowiredArgumentMarker;args.resolveNecessary = true;}catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);}}}for (String autowiredBeanName : autowiredBeanNames) {this.beanFactory.registerDependentBean(autowiredBeanName, beanName);if (logger.isDebugEnabled()) {logger.debug("Autowiring by type from bean name '" + beanName +"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +" to bean named '" + autowiredBeanName + "'");}}return args;
}

封装完参数数组,开始确定构造方法。

筛选构造方法

利用创建的参数数组,执行 argsHolder.getTypeDifferenceWeight(paramTypes) 计算参数值相对于当前候选的构造方法参数类型的差异权重。

// org.springframework.beans.factory.support.ConstructorResolver.ArgumentsHolder
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 = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;return Math.min(rawTypeDiffWeight, typeDiffWeight);
}// 类型差异权重
// MethodInvoker
public static int getTypeDifferenceWeight(Class<?>[] paramTypes, Object[] args) {int result = 0;// 遍历每一个参数类型for (int i = 0; i < paramTypes.length; i++) {// 类型不匹配,返回 int 最大值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;}// 需要的 paramType 是 参数值类型父类的 父类,接着找else if (ClassUtils.isAssignable(paramType, superClass)) {result = result + 2;superClass = superClass.getSuperclass();}else {superClass = null;}}if (paramType.isInterface()) {result = result + 1;}}}return result;
}

在 ArgumentsHolder 中,arguments 代表转换后的参数值,rawArguments 代表解析后未转换的原始值。调用 MethodInvoker#getTypeDifferenceWeight 计算出类型权重差异,取二者之间较小的返回,优先使用原始值计算出的权重差异值作为结果返回。

计算差异值的算法也简单,举个例子。

D 继承 C,C 继承 B,B 实现 A 接口,定义 E(A) 和 E(C)这样两个构造方法,实际传入参数值为 D,计算出的类型差异权重 E(A) 为 5,E(C) 为 2,则取 E(C) 为筛选出的构造方法。

可以看到,如果需要的类型和给定参数值的类型完全一致,类型差异权重为 0,如果类型不匹配,返回 Integer.MAX_VALUE。

需要注意的是,创建参数数组和筛选构造方法实际是在一次循环中完成的,每一次都要为候选的构造方法进行类型转换适配,使其尽量满足当前构造方法,继而计算类型权重差异,取差异最小的构造方法作为 constructorToUse。

确定了 constructorToUse 和 argsToUse 之后,剩下的就是调用 java.lang.reflect.Constructor#newInstance 完成对象的实例化创建。

关键字:变态魔域游戏_appmaker制作app教程_企业网站推广的形式有_百度代理授权查询

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: