Spring 源码阅读:applyPropertyValues 实现

简介

applyPropertyValues 方法是 AbstractAutowireCapableBeanFactory 类中的内部方法,用于给生成的 Bean 对象添加属性。

此方法被 applyBeanPropertyValues 方法所调用,该方法由 AutowireCapableBeanFactory 接口声明,在 AbstractAutowireCapableBeanFactory 类中得到实现,以下为此方法声明的定义:

Apply the property values of the bean definition with the given name to the given bean instance. The bean definition can either define a fully self-contained bean, reusing its property values, or just property values meant to be used for existing bean instances.

This method does not autowire bean properties;it just applies explicitly defined property values.


Use the autowireBeanProperties method to autowire an existing bean instance.


Note: This method requires a bean definition for the given name!


Does not apply standard BeanPostProcessors callbacks or perform any further initialization of the bean. This interface offers distinct, fine-grained operations for those purposes, for example initializeBean. However, InstantiationAwareBeanPostProcessor callbacks are applied, if applicable to the configuration of the instance.


将具有给定名称的 bean 定义的属性值应用于给定的 bean 实例。 bean 定义可以定义一个完全自包含的 bean,重用其属性值,或者只是用于现有 bean 实例的属性值。

此方法不会自动装配 bean 属性;它只是应用显式定义的属性值。

使用 autowireBeanProperties 方法自动装配现有的 bean 实例。

注意:此方法需要给定名称的 bean 定义!

不应用标准的 BeanPostProcessor 回调或执行 bean 的任何进一步初始化。此接口为这些目的提供了不同的、细粒度的操作,例如 initializeBean。但是,如果适用于实例的配置,则会应用InstantiationAwareBeanPostProcessor 回调。

源码

applyPropertyValues

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;
	// 构建缓存 pv 的列表 original
	List<PropertyValue> original;
	// 如果 pvs 是默认实现方式
	if (pvs instanceof MutablePropertyValues) {
		// 可以直接转换
		mpvs = (MutablePropertyValues) pvs;
		// 如果已被转换,不需要再转换
		if (mpvs.isConverted()) {
			// Shortcut: use the pre-converted values as-is.
			try {
				// 使用 BeanWrapper 对属性值进行操作,具体实现在 AbsstractPropertyAccessor 中
				bw.setPropertyValues(mpvs);
				return;
			}
			catch (BeansException ex) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Error setting property values", ex);
			}
		}
		// 不可以直接写入,将 pv 存入缓存表中
		original = mpvs.getPropertyValueList();
	}
	else {
		// 不使用默认实现方式,依然将 pv 存入缓存表中
		original = Arrays.asList(pvs.getPropertyValues());
	}

	// 类型转换
	TypeConverter converter = getCustomTypeConverter();
	if (converter == null) {
		converter = bw;
	}
	BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

	// Create a deep copy, resolving any references for values.
	// 深拷贝,不能指向原 PropertyValue
	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();
			// 如果 value 为 自动注入属性标记
			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);
			}
			// 给定一个 PropertyValue,返回一个转换后的值,必要时解析对工厂中其他 bean 的任何引用
			Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
			Object convertedValue = resolvedValue;
			// 判断可转换且非嵌套属性
			boolean convertible = bw.isWritableProperty(propertyName) &&
					!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
			if (convertible) {
				// 使用 converter 转换属性
				convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
			}
			// Possibly store converted value in merged bean definition,
			// in order to avoid re-conversion for every created bean instance.
			// 可能将转换后的值存储在合并的 bean 定义中,以避免对每个创建的 bean 实例进行重新转换
			if (resolvedValue == originalValue) {
				if (convertible) {
					pv.setConvertedValue(convertedValue);
				}
				deepCopy.add(pv);
			}
			else if (
					// 可转换且为类型化字符串
					convertible && originalValue instanceof TypedStringValue &&
					// 且不为 Dynamic
					!((TypedStringValue) originalValue).isDynamic() &&
					// 且不为 Collection 或 Array
					!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
				pv.setConvertedValue(convertedValue);
				deepCopy.add(pv);
			}
			else {
				resolveNecessary = true;
				deepCopy.add(new PropertyValue(pv, convertedValue));
			}
		}
	}
	// 设置 mpvs 已转换完成
	if (mpvs != null && !resolveNecessary) {
		mpvs.setConverted();
	}

	// Set our (possibly massaged) deep copy.
	try {
		// BeanWrapper 传入 MutablePropertyValues
		bw.setPropertyValues(new MutablePropertyValues(deepCopy));
	}
	catch (BeansException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Error setting property values", ex);
	}
}

setPropertyValues

@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
		throws BeansException {

	List<PropertyAccessException> propertyAccessExceptions = null;
	// 获取需要注入的属性列表
	List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
			((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));

	if (ignoreUnknown) {
		this.suppressNotWritablePropertyException = true;
	}
	try {
		// 遍历每一个 pv,尝试调用子类实现的 setPropertyValue 方法
		for (PropertyValue pv : propertyValues) {
			// setPropertyValue may throw any BeansException, which won't be caught
			// here, if there is a critical failure such as no matching field.
			// We can attempt to deal only with less serious exceptions.
			try {
				setPropertyValue(pv);
			}
			catch (NotWritablePropertyException ex) {
				if (!ignoreUnknown) {
					throw ex;
				}
				// Otherwise, just ignore it and continue...
			}
			catch (NullValueInNestedPathException ex) {
				if (!ignoreInvalid) {
					throw ex;
				}
				// Otherwise, just ignore it and continue...
			}
			catch (PropertyAccessException ex) {
				if (propertyAccessExceptions == null) {
					propertyAccessExceptions = new ArrayList<>();
				}
				propertyAccessExceptions.add(ex);
			}
		}
	}
	finally {
		if (ignoreUnknown) {
			this.suppressNotWritablePropertyException = false;
		}
	}

	// If we encountered individual exceptions, throw the composite exception.
	if (propertyAccessExceptions != null) {
		PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
		throw new PropertyBatchUpdateException(paeArray);
	}
}

setPropertyValue

@Override
public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
	AbstractNestablePropertyAccessor nestedPa;
	try {
		// 通过属性名获取(可以通过递归获取到最末端) AbstractNestablePropertyAccessor
		nestedPa = getPropertyAccessorForPropertyPath(propertyName);
	}
	catch (NotReadablePropertyException ex) {
		throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
				"Nested property in path '" + propertyName + "' does not exist", ex);
	}
	// 将给定的属性名称解析为相应的属性名称标记
	// 例如我们的Person对象中有一个List<String> name的属性,
	// 那么我们在绑定时,需要对List中的元素进行赋值,所有我们会使用name[0],name[1]这种方式来进行绑定,
	// 而PropertyTokenHolder中有三个属性,其中actualName代表name,canonicalName代表整个表达式name[0],而key则代表0这个下标位置
	PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
	nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
}


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

getPropertyAccessorForPropertyPath

/**
 * Recursively navigate to return a property accessor for the nested property path.
 * 递归导航以返回嵌套属性路径的属性访问器。
 * @param propertyPath property path, which may be nested
 * @return a property accessor for the target bean
 */
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
	// 获取第一个嵌套属性分隔符索引
	// 例如若 propertyPath 为 "human.hand.finger",则 pos 返回 human 后的 '.' 下标
	int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
	// Handle nested properties recursively.
	// 获取到 pos 后,可以将 propertyPath 分为两部分
	// 前部分 nestedProperty 和 后半部分 nestedPath
	// 通过 nestedProperty 可以得到其 NestedPropertyAccessor
	// 对于后半部分 nestedPath,继续递归处理,直到获取到最末端属性的 NestedPropertyAccessor
	if (pos > -1) {
		String nestedProperty = propertyPath.substring(0, pos);
		String nestedPath = propertyPath.substring(pos + 1);
		AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
		return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
	}
	else {
		return this;
	}
}
getFirstNestedPropertySeparatorIndex
private static int getNestedPropertySeparatorIndex(String propertyPath, boolean last) {
	boolean inKey = false;
	int length = propertyPath.length();
	int i = (last ? length - 1 : 0);
	// 获取 first 时,终止条件为 i < length
	while (last ? i >= 0 : i < length) {
		// 依次分析路径的字符
		switch (propertyPath.charAt(i)) {
			// 遇到 [ 或 ] 时,控制 inKey 的开闭
			// 即为,inKey 为 true 时,表示在 [] 内部
			case PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR:
			case PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR:
				inKey = !inKey;
				break;
			// 寻找 '.',且如果 '.' 不在 [] 内部,返回下标
			case PropertyAccessor.NESTED_PROPERTY_SEPARATOR_CHAR:
				if (!inKey) {
					return i;
				}
		}
		if (last) {
			i--;
		}
		// 获取 first 时,从前往后处理
		else {
			i++;
		}
	}
	return -1;
}

getPropertyNameTokens

private PropertyTokenHolder getPropertyNameTokens(String propertyName) {
	// 初始 actualName
	String actualName = null;
	List<String> keys = new ArrayList<>(2);
	// index 初始位置
	int searchIndex = 0;
	// 例:name[0]
	// actualName 代表 name
	// canonicalName 代表整个表达式name[0]
	// key 代表 0 这个下标位置
	while (searchIndex != -1) {
		// key 的开始位置位于 [ 标志
		int keyStart = propertyName.indexOf(PROPERTY_KEY_PREFIX, searchIndex);
		// 获得 key 的起始位置后,置 index 为 -1
		searchIndex = -1;
		// 第一轮一定会进入以下逻辑,第二轮后只有存在 [ 标志才会进入
		if (keyStart != -1) {
			// 获取同一层嵌套对应 ] 位置(不会错配)
			// 例如 name[[[]]],keyStart 为第一个 [ ,则通过此方法应获取到最后一个 ]
			int keyEnd = getPropertyNameKeyEnd(propertyName, keyStart + PROPERTY_KEY_PREFIX.length());
			// 存在 ]
			if (keyEnd != -1) {
				if (actualName == null) {
					// actualName 应为 [ 之前的部分( "name[0]" 中的 "name")
					actualName = propertyName.substring(0, keyStart);
				}
				// key 应为 [ 和 ] 之间的值 ( "name[0]" 中的 "0")
				String key = propertyName.substring(keyStart + PROPERTY_KEY_PREFIX.length(), keyEnd);
				// 如果被 '' 或 "" 包裹则去掉
				if (key.length() > 1 && (key.startsWith("'") && key.endsWith("'")) ||
						(key.startsWith("\"") && key.endsWith("\""))) {
					key = key.substring(1, key.length() - 1);
				}
				// 在 keys 中增加 key,继续逻辑
				keys.add(key);
				searchIndex = keyEnd + PROPERTY_KEY_SUFFIX.length();
			}
		}
	}
	PropertyTokenHolder tokens = new PropertyTokenHolder(actualName != null ? actualName : propertyName);
	if (!keys.isEmpty()) {
		tokens.canonicalName += PROPERTY_KEY_PREFIX +
				StringUtils.collectionToDelimitedString(keys, PROPERTY_KEY_SUFFIX + PROPERTY_KEY_PREFIX) +
				PROPERTY_KEY_SUFFIX;
		tokens.keys = StringUtils.toStringArray(keys);
	}
	return tokens;
}
getPropertyNameKeyEnd
/**
 * Parse the given property name into the corresponding property name tokens.
 *
 * 将给定的属性名称解析为相应的属性名称标记。
 *
 * 例如,如 propertyName为 "name[0][0]"
 * 那么 PropertyTokenHolder 应该包含:
 * actualName = "name"
 * keys = {0, 0}
 *
 * @param propertyName the property name to parse
 * @return representation of the parsed property tokens
 */
private int getPropertyNameKeyEnd(String propertyName, int startIndex) {
	// 记录未关闭的前缀数量
	int unclosedPrefixes = 0;
	int length = propertyName.length();
	// 从开始下标开始遍历,遇到 [ 则未闭前缀计数增加,遇到 ] 则减少,如果完全关闭则返回下标值
	// 注意,此时初始前缀并未关闭,即 propertyName="[name[0]name[1]name[2]]"
	// 进入时,startIndex 应为 1,也就是处理的部分为 "name[0]name[1]name[2]]"
	// 因此处理到最后一个 ] 时,才会返回下标,这保证了只返回同一层嵌套的开闭标志下标
	for (int i = startIndex; i < length; i++) {
		switch (propertyName.charAt(i)) {
			case PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR:
				// The property name contains opening prefix(es)...
				unclosedPrefixes++;
				break;
			case PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR:
				if (unclosedPrefixes == 0) {
					// No unclosed prefix(es) in the property name (left) ->
					// this is the suffix we are looking for.
					return i;
				}
				else {
					// This suffix does not close the initial prefix but rather
					// just one that occurred within the property name.
					unclosedPrefixes--;
				}
				break;
		}
	}
	return -1;
}