Spring 5.x Source trip twenty six Detailed getBean

Create a parameter holding unit

I used the example of two factory methods do, in fact, their differences are the same, will complain, it does not matter, we mainly analyze the process works:
Here Insert Picture Description
Here Insert Picture Description

Here Insert Picture Description
First, go get the name of the parameter name parameter probe, in fact, inside is ASMread byte code to operate, mainly LocalVariableTableParameterNameDiscovererthe class, binary stream to read classthe file, and then analyze more complex, are interested can see. Our analysis methods directly on the core of it.

createArgumentArray

Leaving a general case, does not include a xmlsetting mode or parameter values manually set ConstructorArgumentValues, it is the most common form. The number of parameters, traversing parameters, this will involve the index parameter paramIndexmatter, xmlthere will be used, first, the factory method (constructor) and packaged into a common index MethodParametertype of treatment, followed by automatic assembly, parses the parameter object , which is very complicated, said that while the last to be registered and are dependent dependent bean, in fact, do caching, the next can be used directly.

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;
	}

A method of packaging parameters MethodParameter forExecutable

This is the process plant for methods and constructors together into a common form, to facilitate later unitary.

	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 constructor

In fact, the method and the index set in, there is a nested layer, such as listin nested listthis, temporarily do not control, we still according to the general, the nesting is the layer that is 1, if not 1, go back inside to find embedded set type.

	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;
	}

Analytical parameter automatic assembly resolveAutowiredArgument

First, it is judged whether the injection point type InjectionPoint, a method of this type is described, or a constructor parameter or attribute, since these are the places can be automatically injected. If so, it returns direct access to the injection point, or let beanFactoryto resolve dependencies, before that, first MethodParameterencapsulated DependencyDescriptor, that is, the injection point.

	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

Judgment is dependent on what type, to handle different types, of course, we are sure is the last kind of situation, our custom type, see if lazy loading, if not immediately call doResolveDependencyto resolve.

@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 get dependent on type of getDependencyType

If there is property exists and is greater than the nested types 1, will find out the real type, such as List<String>this, Stringthe nest is 2, true type is String. Of course, we are not a property injection, so a direct call MethodParameterof getNestedParameterType.

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

I found a lot of duplicate code, in fact, mostly with processing logic attributes the same, if there is only one layer, it is called directly 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

There is a direct return type, or other processing will be carried out to obtain the parameter type.

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;
	}

Well, here today, we hope to help study and understand, do not spray the Great God see, understand only their own learning, limited capacity, please excuse.

Published 235 original articles · won praise 74 · views 30000 +

Guess you like

Origin blog.csdn.net/wangwei19871103/article/details/105092170