栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring核心源码分析第十九篇refresh流程一createBeanInstance构造方法选择determineCandidateConstructors+autowireConstructor

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring核心源码分析第十九篇refresh流程一createBeanInstance构造方法选择determineCandidateConstructors+autowireConstructor

文章目录
  • 原理分析
  • 原码分析一determineCandidateConstructors
  • 原码分析一autowireConstructor
  • 总结

原理分析

determineCandidateConstructors

  • 1 遍历所有的构造方法,如果有Autowired(required=true)的构造函数且只有一个返回该构造函数
  • 2遍历所有的构造方法,如果有Autowired(required=true)的构造函数且有多个,报错
  • 3 如果有多个注解标注的构造函数,则返回所有注解标注的外加无参构造
  • 4 如果只有一个构造函数返回该构造函数
  • 5 其他情况返回null

autowireConstructor

  • 将所有的候选构造函数排序,排序规则[第一排序规则: public方法优先,第二排序规则:参数数量降序]
  • 设置一个算法,输入构造函数,输出一个整数
  • 判断构造方法能否完成依赖注入,不能跳过该构造函数
  • 算法输出的最小值则作为被选中的构造函数
  • 通过选中的构造函数完成对象实例化
  • 算法根据mbd.isLenientConstructorResolution(默认宽松模式)区分严格模式和宽松模式,不同的模式有不同计算方式
原码分析一determineCandidateConstructors
有注解优先注解 无注解只有一个构造函数则明确 其他不明确后置处理
**
 * 说明: 一套选择机制选择一个构造函数用于构建Object
 * 但是如果找到多个就返回多个 因为无法抉择 交给后续处理autowireConstructor方法处理【sortConstructor 构造之后的那个构造创建处理  public优先 参数数量大的优先】
 *
 *
 * 选择逻辑
 * 1 autowired注解request为true的构造函数有多个,报错
 * 2 autowired注解request为true的构造函数有一个,返回该构造函数
 * 3 autowired注解request为false的构造函数有多个,返回该构造函数集合+无参构造
 * 4 只有一个构造函数 返回该构造函数[可能有注解 可能是多参数 也可能是无参构造]
 * 5 存在多个构造函数 返回null【其无法决定】
 *
 * @param beanClass
 * @param beanName
 * @return
 * @throws BeanCreationException
 *
@Override
@Nullable
public Constructor[] determineCandidateConstructors(Class beanClass, final String beanName)
		throws BeanCreationException {
	...... 删除@lookup改变的mbd的methodOverrides处理代码
	...... 删除缓存相关
	if (candidateConstructors == null) {
		step-1: 获取所有的构造方法作为原始的构造器集合
		Constructor[] rawCandidates = beanClass.getDeclaredConstructors();
		List> candidates = new ArrayList<>(rawCandidates.length);
		@Authwired(required = true)的构造函数
		Constructor requiredConstructor = null;
		无参构造函数
		Constructor defaultConstructor = null;
		采用Kotlin建立的构造函数  这种已经不是java语言了;一般primaryConstructor为null 自行了解Kotlin 相关{现在的JVM支持的不只java一种语言}
		Constructor primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
		非混合构造函数
		int nonSyntheticConstructors = 0;
		step-2: 循环处理所有的构造方法
		for (Constructor candidate : rawCandidates) {
			判断当前的构造方法,属性,类,方法是不是混合类
			if (!candidate.isSynthetic()) { //
				nonSyntheticConstructors++; // +1表示构造方法可用
			}
			else if (primaryConstructor != null) {
				continue;
			}
			step-3 找 @Value 和@Autowired @Inject 标注的构造方法 [ AnnotationAttribute是这些注解的属性和值]
			AnnotationAttributes ann = findAutowiredAnnotation(candidate);
			......删除找父类构造的过程

			step: 3-1 找到了并且注解的required属性为true加入候选者集合
			if (ann != null) {
				if (requiredConstructor != null) {
					throw new BeanCreationException(beanName,
							"Invalid autowire-marked constructor: " + candidate +
							". Found constructor with 'required' Autowired annotation already: " +
							requiredConstructor);
				}
				boolean required = determineRequiredStatus(ann);
				if (required) {
					如果存在多个必要候选者 比如两个@autowired(request=true) 标注的构造方法 则会抛出异常
					if (!candidates.isEmpty()) {
						throw new BeanCreationException(beanName,
								"Invalid autowire-marked constructors: " + candidates +
								". Found constructor with 'required' Autowired annotation: " +
								candidate);
					}
					requiredConstructor = candidate;
				}
				candidates.add(candidate);
			}
			else if (candidate.getParameterCount() == 0) {
			    step-4 没有注解并且参数为0 设为无参构造
				defaultConstructor = candidate;
			}
		}

	    candidates不为空 返回所有选择到的构造函数外加无参构造函数
		if (!candidates.isEmpty()) {
			if (requiredConstructor == null) {
				if (defaultConstructor != null) {
					candidates.add(defaultConstructor);
				}
				
			}
			candidateConstructors = candidates.toArray(new Constructor[0]);
		}
		else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
			没有@autowired等注解标注 且一共只有一个构造函数  返回该构造函数
			candidateConstructors = new Constructor[] {rawCandidates[0]};
		}
		删除kotlin语言相关
		else {
			其他情况一律不加考虑 依赖下游自行决定选择何种构造函数  下游实际通过排序sortConstructor完成多个构造函数的选择
			candidateConstructors = new Constructor[0];
		}
		this.candidateConstructorsCache.put(beanClass, candidateConstructors);
	}
	返回一个说明后面会选择  存在多个这个返回null 交给autowireConstructor方法自行选择
	return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
原码分析一autowireConstructor
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor[] chosenCtors, @Nullable Object[] explicitArgs) {
	......删除大量其他代码以方便理解
	BeanWrapperImpl bw = new BeanWrapperImpl();
	step-1 	对所有的构造函数排序 按照访问限制修饰符进行排序public优先 按照方法参数进行排序,数量多的优先
	AutowireUtils.sortConstructors(candidates);
	
	step-2 开始算法计算: 
	算法minTypeDiffWeight的初始值
	int minTypeDiffWeight = Integer.MAX_VALUE;
	for (Constructor candidate : candidates) {
		step-2.1 如果寻找构造注入的参数报错则跳过改构造函数
		ArgumentsHolder argsHolder;
		if (resolvedValues != null) {
			try {
				argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
						getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
			}
			catch (UnsatisfiedDependencyException ex) {
				如果寻找构造注入的参数报错则跳过改构造函数
				continue;
			}
		}

		step-2.2 设计一种算法计算typeDiffWeight的值,所有的构造函数中typeDiffWeight最小的值为被选中的构造函数
		- 如果typeDiffWeight都相同 则按照排序的规则选中第一个构造函数
		- 算法依据isLenientConstructorResolution区分严格模式还是宽松模式 默认宽松模式
		int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
				argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
		if (typeDiffWeight < minTypeDiffWeight) {
			step-2.3 如果当前typeDiffWeight小于minTypeDiffWeight则更新minTypeDiffWeight
			constructorToUse = candidate;
			argsHolderToUse = argsHolder;
			argsToUse = argsHolder.arguments;
			minTypeDiffWeight = typeDiffWeight;
			ambiguousConstructors = null;
		}
	}

	step-3 实例化对象
	bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
	return bw;
}
总结
  • 分析了如何选择分区构造函数 determineCandidateConstructors
  • 分析了存在多个构造函数如何通过算法实现构造的选择 排序 + 算法
  • 算法细节并未讲解 大家可以看方法说明
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/696516.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号