【Spring 源码】DI(依赖注入) 的加载原理(二)

文章目录

  • 【Spring 源码】DI(依赖注入) 的加载原理(二)
  • 一、准备注入
  • 1. 进行注入的准备工作
  • 2. 进行值的转换并注入
  • 二、进行注入
  • 1. 解析设置的值
  • 2. 选择策略
  • 3. 进行注入

一、准备注入

在准备注入的过程中,会具体判断用户在配置文件中设置的自动装配的类型,根据自动装配 byName 或 byType 来判断具体走哪个方法。当然,如果自动装配的规则是使用 construct,则是在前面进行 Bean 的构造的时候就已经完成了,所以在这边不会涉及到。

1. 进行注入的准备工作

主要代码:populateBean()

在很多进行初始化的地方,我们都能看到会有前后置处理器的存在,Spring 项目为了方便用户进行处理,特地留了许多口子留给用户进行自定义实现。

protected void populateBean(
	String beanName, 
	RootBeanDefinition mbd, 
	@Nullable BeanWrapper bw
) {
	if (bw == null) {
		if (mbd.hasPropertyValues()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
		}
		else {
			return;
		}
	}

	// 在进行注入之前还可以对 Bean 进行改变处理,提供了一个前置方法,用户可以通过实现 InstantiationAwareBeanPostProcessor 来使用 postProcessAfterInstantiation 对 Bean 进行处理
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}
	}

	// 获取属性值,只有在用到 <property> 标签的时候才会获取到
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	// 根据自动装配的方式来进行自动装配,在这个过程中只是注册
	int resolvedAutowireMode = mbd.getResolvedAutowireMode();
	if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
		// byName 方式装配
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		// byType 方式装配
		if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}
		pvs = newPvs;
	}

	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

	// 进行过滤
	PropertyDescriptor[] filteredPds = null;
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			// 对要进行注入的值再次使用自定义的 postProcessProperties 进行处理
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					// 进行过滤
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					// 如果上面没进行处理,这边会使用另一个处理值的方法 postProcessPropertyValues 进行处理
					pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
	}

	// 检查依赖
	if (needsDepCheck) {
		if (filteredPds == null) {
			filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		}
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}

	// 对值进行转换并注入,只有在用到 <property> 标签的时候才会在这进行注入
	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}

2. 进行值的转换并注入

主要代码:applyPropertyValues()

applyPropertyValues() 方法中,提供了类型的转换器,如果用户需要进行类型的转换,则可以自定义实现转换器方法,比如将 json 中的值转换为相对应的枚举类。

protected void applyPropertyValues(
	String beanName, 
	BeanDefinition mbd, 
	BeanWrapper bw, 
	PropertyValues pvs
) {
	if (pvs.isEmpty()) {
		return;
	}

	if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
		((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
	}

	MutablePropertyValues mpvs = null;
	List<PropertyValue> original;

	if (pvs instanceof MutablePropertyValues) {
		mpvs = (MutablePropertyValues) pvs;
		// 如果已经转换过了,则不需要再进行
		if (mpvs.isConverted()) {
			try {
				bw.setPropertyValues(mpvs);
				return;
			}
			catch (BeansException ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
			}
		}
		// 获取属性值的列表
		original = mpvs.getPropertyValueList();
	}
	else {
		original = Arrays.asList(pvs.getPropertyValues());
	}

	// 获取自定义的类型转换器
	TypeConverter converter = getCustomTypeConverter();
	if (converter == null) {
		converter = bw;
	}
	// 获取解析器
	BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

	// 深拷贝创建副本
	List<PropertyValue> deepCopy = new ArrayList<>(original.size());
	boolean resolveNecessary = false;
	for (PropertyValue pv : original) {
		if (pv.isConverted()) {
			deepCopy.add(pv);
		}
		else {
			String propertyName = pv.getName();
			Object originalValue = pv.getValue();
			if (originalValue == AutowiredPropertyMarker.INSTANCE) {
				Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
				if (writeMethod == null) {
					throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
				}
				originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
			}
			// 判断注入的类型是否是方法中的几项,如果是,会做其他操作
			Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
			Object convertedValue = resolvedValue;
			// 是否可以转换
			boolean convertible = bw.isWritableProperty(propertyName) &&
					!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
			if (convertible) {
				// 如果需要转换类型,会在此进行转换,可以扩展转换器
				convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
			}
			// 存储转换的值,避免每次都进行转换
			if (resolvedValue == originalValue) {
				if (convertible) {
					pv.setConvertedValue(convertedValue);
				}
				deepCopy.add(pv);
			}
			else if (convertible && originalValue instanceof TypedStringValue &&
					!((TypedStringValue) originalValue).isDynamic() &&
					!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
				pv.setConvertedValue(convertedValue);
				deepCopy.add(pv);
			}
			else {
				resolveNecessary = true;
				deepCopy.add(new PropertyValue(pv, convertedValue));
			}
		}
	}

	// 设置转换成功的标志
	if (mpvs != null && !resolveNecessary) {
		mpvs.setConverted();
	}

	// 进行注入
	try {
		bw.setPropertyValues(new MutablePropertyValues(deepCopy));
	}
	catch (BeansException ex) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
	}
}

二、进行注入

1. 解析设置的值

主要代码:AbstractNestablePropertyAccessor#setPropertyValues()

解析值会将 <property> 标签中设置的 value 进行解析,而且在这边如果有 json 类型或者数组类型的值传入,还会进行下标值的解析。通过是否有下标值来判断具体该执行普通的获取值的方法还是需要使用下标值来获取具体值的方法。

@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
	PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
	if (tokens == null) {
		String propertyName = pv.getName();
		AbstractNestablePropertyAccessor nestedPa;
		try {
			nestedPa = getPropertyAccessorForPropertyPath(propertyName);
		}
		catch (NotReadablePropertyException ex) {
			throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, "Nested property in path '" + propertyName + "' does not exist", ex);
		}
		// 如果是解析到数组或者json之类的,则会获取其中的下标值
		tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
		if (nestedPa == this) {
			pv.getOriginalPropertyValue().resolvedTokens = tokens;
		}
		// 会根据解析获取到的 token 来进行判断
		nestedPa.setPropertyValue(tokens, pv);
	}
	else {
		// 会根据解析获取到的 token 来进行判断
		setPropertyValue(tokens, pv);
	}
}

2. 选择策略

主要代码:AbstractNestablePropertyAccessor#setPropertyValue()

如果在之前解析到下标值并封装成 token,则会在这边根据下标值的有无实行不同的方法。普通的 Bean 注入会走 processLocalProperty()

如果遇到 param[0] 或者 param[index] 之类的则会走 processKeyedProperty()

protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
	if (tokens.keys != null) {
		processKeyedProperty(tokens, pv);
	}
	else {
		processLocalProperty(tokens, pv);
	}
}

3. 进行注入

主要代码:AbstractNestablePropertyAccessor#processLocalProperty()

private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
	PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
	if (ph == null || !ph.isWritable()) {
		if (pv.isOptional()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Ignoring optional value for property '" + tokens.actualName + "' - property not found on bean class [" + getRootClass().getName() + "]");
			}
			return;
		}
		else {
			throw createNotWritablePropertyException(tokens.canonicalName);
		}
	}

	Object oldValue = null;
	try {
		// 获取属性值
		Object originalValue = pv.getValue();
		Object valueToApply = originalValue;
		if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
			if (pv.isConverted()) {
				valueToApply = pv.getConvertedValue();
			}
			else {
				// 获取值
				if (isExtractOldValueForEditor() && ph.isReadable()) {
					try {
						oldValue = ph.getValue();
					}
					catch (Exception ex) {
						if (ex instanceof PrivilegedActionException) {
							ex = ((PrivilegedActionException) ex).getException();
						}
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read previous value of property '" + this.nestedPath + tokens.canonicalName + "'", ex);
						}
					}
				}
				// 进行类型转换
				valueToApply = convertForProperty(tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
			}
			pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
		}
		// 这边会有两种类型注入,一种是通过方法进行注入,还有一种是通过类的属性直接设置
		ph.setValue(valueToApply);
	}
	catch (TypeMismatchException ex) {
		throw ex;
	}
	catch (InvocationTargetException ex) {
		PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
				getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
		if (ex.getTargetException() instanceof ClassCastException) {
			throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
		}
		else {
			Throwable cause = ex.getTargetException();
			if (cause instanceof UndeclaredThrowableException) {
				cause = cause.getCause();
			}
			throw new MethodInvocationException(propertyChangeEvent, cause);
		}
	}
	catch (Exception ex) {
		PropertyChangeEvent pce = new PropertyChangeEvent(
				getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
		throw new MethodInvocationException(pce, ex);
	}
}