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

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

Spring 属性注入(四)属性键值对 - PropertyValue的更多相关文章

  1. Learning Spark 第四章——键值对处理

    本章主要介绍Spark如何处理键值对.K-V RDDs通常用于聚集操作,使用相同的key聚集或者对不同的RDD进行聚集.部分情况下,需要将spark中的数据记录转换为键值对然后进行聚集处理.我们也会对 ...

  2. Spring @Value注入static属性

    import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Com ...

  3. Spring 中注入 properties 中的值

    <bean id="ckcPlaceholderProperties" class="org.springframework.beans.factory.confi ...

  4. 解决Spring Boot 使用RedisTemplate 存储键值出现乱码 \xac\xed\x00\x05t\x00

    spring-data-redis的RedisTemplate<K, V>模板类在操作redis时默认使用JdkSerializationRedisSerializer来进行序列化解决方法 ...

  5. Spring 中IOC(控制反转)&& 通过SET方式为属性注入值 && Spring表达式

    ### 1. Spring IoC IoC:Inversion of control:控制反转:在传统开发模式下,对象的创建过程和管理过程都是由开发者通过Java程序来实现的,操作权在开发者的Java ...

  6. 六 Spring属性注入的四种方式:set方法、构造方法、P名称空间、SPEL表达式

    Spring的属性注入: 构造方法的属性注入 set方法的属性注入

  7. Spring中对象和属性的注入方式

    一:Spring的bean管理 1.xml方式 bean实例化三种xml方式实现 第一种 使用类的无参数构造创建,首先类中得有无参构造器(重点) 第二种 使用静态工厂创建 (1)创建静态的方法,返回类 ...

  8. Java Spring-注解进行属性注入

    2017-11-06 21:19:43 一.Spring的注解装配BeanSpring2.5 引入使用注解去定义Bean @Component 描述Spring框架中Bean Spring的框架中提供 ...

  9. .NET领域最为流行的IOC框架之一Autofac WebAPI2使用Autofac实现IOC属性注入完美解决方案 AutoFac容器初步

    .NET领域最为流行的IOC框架之一Autofac   一.前言 Autofac是.NET领域最为流行的IOC框架之一,微软的Orchad开源程序使用的就是Autofac,Nopcommerce开源程 ...

随机推荐

  1. python+爬虫+签名

    在公众号,看到一个比较好玩的程序.它使用post的来传送请求,以前没有遇到过.可能是自己,写的程序太少了.查了一下post的用法: 通常,你想要发送一些编码为表单形式的数据——非常像一个 HTML 表 ...

  2. quast-lg

    1.官网简介 http://cab.spbu.ru/software/quast-lg/ QUAST- lg是QUAST的一个扩展,用于评估大型基因组装配(直至哺乳动物大小).QUAST- lg从5. ...

  3. cdh 安装系列1-- manager 6.01 安装

    一.如果是远程centos安装,请参考我得博客,通过xmanager 链接centos桌面 二.Non-production Installation Ideal for trying Clouder ...

  4. SQLMAP自动注入(四):枚举

    --privileges 查询权限 -U 指定用户 -CU指定当前用户 --schema 查询所有的数据 --batch 批处理,自动选择默认选项 --exclude-sysdbs 排除系统库的查询 ...

  5. 无线渗透wpa加密路由器

    破解wpa加密路由器的原理不同于破解wep加密路由器,只能通过暴力破解获取. 但是获取握手keystream的原理差不多 首先杀死可能会和破解冲突的进程 airmon-ng check kill 开启 ...

  6. Fiddler抓包域名过滤(转载)

    转载自 http://www.cnblogs.com/111testing/p/6440480.html Fiddler抓包域名过滤 我们在用Fiddler抓包的时候会抓到很多不需要的数据包,我们怎样 ...

  7. web.config中连接字符串的读写和加密解密

    转载:https://www.cnblogs.com/shuai/articles/2248703.html 1.先来看看如何在web.config中写入数据库连接字符串.打开web.config文件 ...

  8. 第十一章 串 (b1)串匹配

  9. vue-webpack项目自动打包压缩成zip文件批处理

    为什么需要这个? 使用vue框架开发项目,npm run build这个命令会一直用到,如果需要给后端发包,那你还要打包成zip格式的压缩包,特别是项目提测的时候,一天可能要执行重复好几次,所以才有了 ...

  10. [剑指Offer]53-在排序数组中查找数字(二分查找)

    题目一 数字在排序数组中出现的个数 题目描述 统计一个数字在排序数组中出现的次数. 解决思路 写两个二分查找分别找第一个和最后一个该数字,然后可直接出计算有几个该数字.时间复杂度为O(logn). 这 ...