欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring 5.x 源码之旅二十getBean详解六

程序员文章站 2024-01-08 11:08:06
...

创建参数持有器

我就用两个工厂方法来做例子,其实他们差异是一样的,会报错,没关系,我们主要分析过程原理:
Spring 5.x 源码之旅二十getBean详解六
Spring 5.x 源码之旅二十getBean详解六

Spring 5.x 源码之旅二十getBean详解六
首先会用参数名字探测器去获取参数的名字,其实内部是用ASM读取字节码来操作的,主要是LocalVariableTableParameterNameDiscoverer这个类,二进制流读取class文件,然后分析,比较复杂,有兴趣的可以去看。我们直接就核心方法分析吧。

createArgumentArray

留下了一般的情况,不包括用xml方式设置参数值或者手动设置了ConstructorArgumentValues,就是最普通的形式。根据参数的数量,开始遍历参数,这里就会涉及参数的索引paramIndex 啦,xml里会用到,首先将工厂方法(构造方法)和索引封装成一个通用的MethodParameter类型处理,然后进行自动装配,解析出参数对象,里面很复杂,一会儿说,最后要注册依赖和被依赖的bean,其实就是做缓存,下次可以直接用。

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();
		TypeConverter 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);//装配的bean名字
		//带参数的话
		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) {
				...
			}
			if (valueHolder != null) {
				...
			}
			else {
				//获取统一的方法参数类型
				MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);

				if (!autowiring) {
					throw new UnsatisfiedDependencyException(
					...
				}
				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);
				}
			}
		}
		//注册依赖的bean
		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;
	}

MethodParameter的forExecutable封装方法参数

这里就是将工厂方法和构造方法一起处理成通用形式,方便后面统一处理。

	public static MethodParameter forExecutable(Executable executable, int parameterIndex) {
		if (executable instanceof Method) {
			return new MethodParameter((Method) executable, parameterIndex);
		}
		else if (executable instanceof Constructor) {
			return new MethodParameter((Constructor<?>) executable, parameterIndex);
		}
		else {
			throw new IllegalArgumentException("Not a Method/Constructor: " + executable);
		}
	}

MethodParameter的构造方法

其实就是把方法和索引设置进去,还有一个嵌套层,比如list里嵌套list这种,暂时不用管,我们还是按一般的来,嵌套就是层就是1,如果不是1,后面会去查找内部的嵌套类型。

	public MethodParameter(Method method, int parameterIndex, int nestingLevel) {
		Assert.notNull(method, "Method must not be null");
		this.executable = method;
		this.parameterIndex = validateIndex(method, parameterIndex);
		this.nestingLevel = nestingLevel;
	}

resolveAutowiredArgument解析自动装配参数

首先判断是否是注入点类型InjectionPoint ,这个类型就是描述一个方法或者构造器的参数或者一个属性,因为这些都是可以自动注入的地方。如果是的话,就直接获取注入点返回,否则就让beanFactory来解析依赖,在这之前,先把MethodParameter 封装成DependencyDescriptor,也就是注入点。

	protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
			@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {

		Class<?> paramType = param.getParameterType();
		if (InjectionPoint.class.isAssignableFrom(paramType)) {//是否是注入点类型,比如DependencyDescriptor
			InjectionPoint injectionPoint = currentInjectionPoint.get();
			if (injectionPoint == null) {
				throw new IllegalStateException("No current InjectionPoint available for " + param);
			}
			return injectionPoint;
		}
		try {//beanFactory解析依赖
			return this.beanFactory.resolveDependency(
					new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
		}
		catch (NoUniqueBeanDefinitionException ex) {
			throw ex;
		}
		catch (NoSuchBeanDefinitionException ex) {
			if (fallback) {
				...
			}
			throw ex;
		}
	}

DefaultListableBeanFactory的resolveDependency

判断依赖是什么类型,根据不同类型来处理,当然我们肯定是最后的那种情况,我们自定义的类型,看看是否是懒加载的,如果不是就立即调用doResolveDependency来解析。

@Override
	@Nullable
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		//设置参数名字探索器
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {//Optional类型
			return createOptionalDependency(descriptor, requestingBeanName);
		}//是对象工厂类型或者对象提供者类型
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}//java扩展的注入类
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {//我们自己只能的类型,先看是否是懒加载,是的话就直接返回,否则要去解析依赖
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

MethodParameter的getDependencyType获取依赖类型

这里如果有属性存在,而且嵌套类型大于1,就会找出真实类型,比如List<String>这种,String的嵌套就是2,真实类型就是String。当然我们不是属性注入,所以直接调用MethodParametergetNestedParameterType

public Class<?> getDependencyType() {
		if (this.field != null) {
			if (this.nestingLevel > 1) {
				Type type = this.field.getGenericType();
				for (int i = 2; i <= this.nestingLevel; i++) {
					if (type instanceof ParameterizedType) {
						Type[] args = ((ParameterizedType) type).getActualTypeArguments();
						type = args[args.length - 1];
					}
				}
				if (type instanceof Class) {
					return (Class<?>) type;
				}
				else if (type instanceof ParameterizedType) {
					Type arg = ((ParameterizedType) type).getRawType();
					if (arg instanceof Class) {
						return (Class<?>) arg;
					}
				}
				return Object.class;
			}
			else {
				return this.field.getType();
			}
		}
		else {
			return obtainMethodParameter().getNestedParameterType();
		}
	}

MethodParameter的getNestedParameterType

发现了大量重复代码,其实大部分是跟属性的处理逻辑一样的,如果只有1层,就直接调用getParameterType

public Class<?> getNestedParameterType() {
		if (this.nestingLevel > 1) {
			Type type = getGenericParameterType();
			for (int i = 2; i <= this.nestingLevel; i++) {
				if (type instanceof ParameterizedType) {
					Type[] args = ((ParameterizedType) type).getActualTypeArguments();
					Integer index = getTypeIndexForLevel(i);
					type = args[index != null ? index : args.length - 1];
				}
				// TODO: Object.class if unresolvable
			}
			if (type instanceof Class) {
				return (Class<?>) type;
			}
			else if (type instanceof ParameterizedType) {
				Type arg = ((ParameterizedType) type).getRawType();
				if (arg instanceof Class) {
					return (Class<?>) arg;
				}
			}
			return Object.class;
		}
		else {
			return getParameterType();
		}
	}
DependencyDescriptor的getNestedParameterType

存在类型就直接返回了,否则就要进行其他处理获得参数类型。

public Class<?> getParameterType() {
		Class<?> paramType = this.parameterType;
		if (paramType != null) {
			return paramType;
		}
		if (getContainingClass() != getDeclaringClass()) {
			paramType = ResolvableType.forMethodParameter(this, null, 1).resolve();
		}
		if (paramType == null) {
			paramType = computeParameterType();
		}
		this.parameterType = paramType;
		return paramType;
	}

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。