zoukankan      html  css  js  c++  java
  • Spring 属性注入(四)属性键值对

    Spring 属性注入(四)属性键值对 - PropertyValue

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)

    PropertyValue 和 PropertyValues 都位于 org.springframework.beans 包下,是 bean 属性键值对的封装,缓存了对 key-value 解析相关的信息,避免重复解析。

    一、PropertyValue

    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 类图

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

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    【BZOJ 4581】【Usaco2016 Open】Field Reduction
    【BZOJ 4582】【Usaco2016 Open】Diamond Collector
    【BZOJ 4580】【Usaco2016 Open】248
    【BZOJ 3754】Tree之最小方差树
    【51Nod 1501】【算法马拉松 19D】石头剪刀布威力加强版
    【51Nod 1622】【算法马拉松 19C】集合对
    【51Nod 1616】【算法马拉松 19B】最小集合
    【51Nod 1674】【算法马拉松 19A】区间的价值 V2
    【BZOJ 2541】【Vijos 1366】【CTSC 2000】冰原探险
    【BZOJ 1065】【Vijos 1826】【NOI 2008】奥运物流
  • 原文地址:https://www.cnblogs.com/binarylei/p/10278556.html
Copyright © 2011-2022 走看看