Spring 属性注入(四)属性键值对 - PropertyValue
Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)
PropertyValue 和 PropertyValues 都位于 org.springframework.beans 包下,是 bean 属性键值对的封装,缓存了对 key-value 解析相关的信息,避免重复解析。
一、PropertyValue
-
AttributeAccessor
可以访问对象的属性或将属性附加到对象上。 -
BeanMetadataElement
持有属性信息的对象。 -
BeanMetadataAttributeAccessor
实现了 AttributeAccessor 和 BeanMetadataElement 两个接口,属性为 BeanMetadataAttribute 对象。 -
PropertyValue
属性键值对。
有一点不太明白 PropertyValue 表示一个属性键值对,PropertyValues 表示多个属性键值对,那 PropertyValue 为什么还要继承 AttributeAccessor 接口,AttributeAccessor 可以对多个属性进行管理。
1.1 AttributeAccessor
public interface AttributeAccessor {
// 对属性进行增删改查
void setAttribute(String name, @Nullable Object value);
Object getAttribute(String name);
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
}
AttributeAccessor 接口的实现类为 AttributeAccessorSupport,在这个类中维护一个 Map<String, Object> attributes = new LinkedHashMap<>()
,对属性进行增删改查。
1.2 BeanMetadataElement
public interface BeanMetadataElement {
Object getSource();
}
BeanMetadataAttributeAccessor 的实现了 AttributeAccessor 和 BeanMetadataElement 两个接口,内部维护的是 <propertyName, BeanMetadataAttribute> 键值对,BeanMetadataAttribute 是一个持有属性对和源的对象。
public class BeanMetadataAttribute implements BeanMetadataElement {
// 属性 key - value
private final String name;
private final Object value;
// 属性所属的对象
private Object source;
}
1.3 PropertyValue
PropertyValue 缓存了对 key-value 解析相关的信息,避免重复解析。如 AbstractNestablePropertyAccessor#processLocalProperty 进行属性注入时,会判断是否需要对属性值进行类型转换。相关字段如下:
// 1.1 属性名称
private final String name;
// 1.1 属性值
private final Object value;
// 2.1 属性值是否为 Optional
private boolean optional = false;
// 2.2 属性值是否已经进行了类型转换
private boolean converted = false;
// 2.3 类型转换后的属性值
private Object convertedValue;
// 3.1 属性值是否需要进行类型转换,如果转换前后对象都是同一个,说明不用转换
volatile Boolean conversionNecessary;
// 3.2 缓存解析后的属性名称,如 attr['info']['name']
transient volatile Object resolvedTokens;
直接设置 convertedValue 值时 converted = true。
public synchronized void setConvertedValue(@Nullable Object value) {
this.converted = true;
this.convertedValue = value;
}
二、PropertyValues
PropertyValues 表示多个属性键值对,接口如下:
public interface PropertyValues extends Iterable<PropertyValue> {
// @since 5.1
default Iterator<PropertyValue> iterator() {
return Arrays.asList(getPropertyValues()).iterator();
}
PropertyValue[] getPropertyValues();
PropertyValue getPropertyValue(String propertyName);
boolean contains(String propertyName);
boolean isEmpty();
// old 和当前的对比,返回当前有而 old 没有的元素
PropertyValues changesSince(PropertyValues old);
}
PropertyValues 的默认实现为 MutablePropertyValues,内部也是维护了一个 List<PropertyValue> propertyValueList
集合。MutablePropertyValues 会将属性值转换成 PropertyValue 进行存储。
(1) 属性
private final List<PropertyValue> propertyValueList;
// 已经解析过的 PropertyValue
private Set<String> processedProperties;
private volatile boolean converted = false;
(2) addPropertyValues
可以将 Map、PropertyValue 属性添加到集合中,MutablePropertyValues 统一封装成 PropertyValue 进行存储。
public MutablePropertyValues addPropertyValues(@Nullable Map<?, ?> other) {
if (other != null) {
other.forEach((attrName, attrValue) -> addPropertyValue(
new PropertyValue(attrName.toString(), attrValue)));
}
return this;
}
// 所有类型的属性键值对都会转换成 PropertyValue 后进行存储
public MutablePropertyValues addPropertyValue(PropertyValue pv) {
for (int i = 0; i < this.propertyValueList.size(); i++) {
PropertyValue currentPv = this.propertyValueList.get(i);
if (currentPv.getName().equals(pv.getName())) {
pv = mergeIfRequired(pv, currentPv);
setPropertyValueAt(pv, i);
return this;
}
}
this.propertyValueList.add(pv);
return this;
}
注意如果属性值是 Mergeable 类型会先合并,代码如下:
private PropertyValue mergeIfRequired(PropertyValue newPv, PropertyValue currentPv) {
Object value = newPv.getValue();
if (value instanceof Mergeable) {
Mergeable mergeable = (Mergeable) value;
if (mergeable.isMergeEnabled()) {
Object merged = mergeable.merge(currentPv.getValue());
return new PropertyValue(newPv.getName(), merged);
}
}
return newPv;
}
Mergeable 的子类有 ManagedSet、ManagedList、ManagedMap、ManagedProperties、ManagedArray,合并也很简单,以 ManagedList 为例:
public List<E> merge(@Nullable Object parent) {
List<E> merged = new ManagedList<>();
merged.addAll((List<E>) parent);
merged.addAll(this);
return merged;
}
(3) getPropertyValue
public PropertyValue getPropertyValue(String propertyName) {
for (PropertyValue pv : this.propertyValueList) {
if (pv.getName().equals(propertyName)) {
return pv;
}
}
return null;
}
(4) changesSince
查找相对 old 发生变化的所有元素。
@Override
public PropertyValues changesSince(PropertyValues old) {
MutablePropertyValues changes = new MutablePropertyValues();
// 1. 返回空集合
if (old == this) {
return changes;
}
// 2. 返回 propertyValueList 中有而 old 没有的元素集合
for (PropertyValue newPv : this.propertyValueList) {
PropertyValue pvOld = old.getPropertyValue(newPv.getName());
if (pvOld == null || !pvOld.equals(newPv)) {
changes.addPropertyValue(newPv);
}
}
return changes;
}
每天用心记录一点点。内容也许不重要,但习惯很重要!