Spring 屬性注入(四)屬性鍵值對 - PropertyValue

Spring 屬性注入(四)屬性鍵值對 - PropertyValue

Spring 系列目錄(http://www.javashuo.com/article/p-hskusway-em.html)html

PropertyValue 和 PropertyValues 都位於 org.springframework.beans 包下,是 bean 屬性鍵值對的封裝,緩存了對 key-value 解析相關的信息,避免重複解析。java

1、PropertyValue

PropertyValue 類圖

  • AttributeAccessor 能夠訪問對象的屬性或將屬性附加到對象上。
  • BeanMetadataElement 持有屬性信息的對象。
  • BeanMetadataAttributeAccessor 實現了 AttributeAccessor 和 BeanMetadataElement 兩個接口,屬性爲 BeanMetadataAttribute 對象。
  • PropertyValue 屬性鍵值對。

有一點不太明白 PropertyValue 表示一個屬性鍵值對,PropertyValues 表示多個屬性鍵值對,那 PropertyValue 爲何還要繼承 AttributeAccessor 接口,AttributeAccessor 能夠對多個屬性進行管理。spring

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 是一個持有屬性對和源的對象。ide

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 進行屬性注入時,會判斷是否須要對屬性值進行類型轉換。相關字段以下:ui

// 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。this

public synchronized void setConvertedValue(@Nullable Object value) {
    this.converted = true;
    this.convertedValue = value;
}

2、PropertyValues

PropertyValues 類圖

PropertyValues 表示多個屬性鍵值對,接口以下:spa

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 進行存儲。code

(1) 屬性htm

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

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索