学成路更宽,吊打面试官。 ——小马哥

简介

大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring核心编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。 分为基础篇、进阶篇、源码篇。玩游戏看颜色,学技术看版本,本系列以 Spring 5.2.0.RELEASE 版本为基础进行介绍。 祝小伙伴早日学有所成。

Spring 类型转换的实现

  1. 基于 JavaBeans 接口的类型转换现实

  2. Spring 3.0+ 通用类型转换实现

使用场景

场景 基于 JavaBeans 接口的类型转换实现 Spring 3.0+ 通用类型转换实现
数据绑定 YES YES
BeanWrapper YES YES
Bean 属性类型转换 YES YES
外部化属性类型转换 NO YES

基于 JavaBeans 接口的类型转换

  • 核心职责:将 String 类型的内容转化为目标类型的对象
  • 扩展原理
    1. Spring 框架将文本内容传递到 PropertyEditor 实现的 setAsText(String) 方法
    2. PropertyEditor#setAsText(String) 方法实现将 String 类型转化为目标类型的对象
    3. 将目标类型的对象传入 PropertyEditor#setValue(Object) 方法
    4. PropertyEditor#setValue(Object) 方法实现需要临时存储传入对象
    5. Spring 框架将通过 PropertyEditor#getValue() 方法获取类型转换后的对象

示例

public class StringToPropertiesPropertyEditor extends PropertyEditorSupport {private final Properties properties = new Properties();// 1. 实现 setAsText(String) 方法@Overridepublic void setAsText(String text) throws IllegalArgumentException {try {if (properties.size() < 1) {// 2. 将 String 类型转换成 Properties 转换properties.load(new StringReader(text));setValue(properties);return;}} catch (IOException e) {throw new IllegalArgumentException(e);}// 3. 进行临时存储 下一步通过 getValue() 获取setValue(properties.getProperty(text));}@Overridepublic String getAsText() {Properties properties = (Properties) getValue();StringBuilder textBuilder = new StringBuilder();for (Map.Entry<Object, Object> entry : properties.entrySet()) {textBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append(System.getProperty("line.separator"));}return textBuilder.toString();}
}public class PropertyEditorDemo {public static void main(String[] args) {// 模拟 Spring Framework 操作String text = "mame = 文海";PropertyEditor propertyEditor = new StringToPropertiesPropertyEditor();// 传递 String 类型的内容propertyEditor.setAsText(text);System.out.println(propertyEditor.getValue());System.out.println(propertyEditor.getAsText());}
}

Spring 内建 PropertyEditor 扩展

在 org.springframework.beans.propertyeditors 包下

转换场景 实现类
String -> Byte 数组 ByteArrayPropertyEditor
String -> Char CharacterEditor
String -> Char 数组 CharArrayPropertyEditor
String -> Charset CharsetEditor
String -> Class ClassEditor
String -> Cuurency CurrencyEditor

自定义 PropertyEditor 扩展

一、扩展模式

  • 扩展 PropertyEditorSupport 类

二、 实现 PropertyEditorRegistrar

  • 实现 registerCustomEditors(PropertyEditorRegistry) 方法
  • 将 PropertyEditorRegistry 实现注册为 Spring Bean

三、 向 PropertyEditorRegistry 注册自定义 PropertyEditor 实现

  • 通用类型实现 registerCustomEditor(Class<?>, PropertyEditor)
  • Java Bean 属性类型实现:registerCustomEditor(Class<?>, String, PropertyEditor)
public class User  {private Properties context;public Properties getContext() {return context;}public void setContext(Properties context) {this.context = context;}@Overridepublic String toString() {return "User{" +"context=" + context +'}';}
}
public class CustomizedPropertyEditorRegistrar implements PropertyEditorRegistrar {@Overridepublic void registerCustomEditors(PropertyEditorRegistry registry) {//  Java Bean 属性类型转换registry.registerCustomEditor(User.class, "user.context", new StringToPropertiesPropertyEditor());}vv
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttps://www.springframework.org/schema/util/spring-util.xsd"><bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"><property name="propertyEditorRegistrars"><list><ref bean="customizedPropertyEditorRegistrar"/></list></property></bean><bean name="customizedPropertyEditorRegistrar" class="com.wenhai.spring.conversion.CustomizedPropertyEditorRegistrar"/><bean class="com.wenhai.xiaomage.spring.ioc.overview.dependency.domain.User" id="user"><property name="context"><value>id = 1name = wenhai</value></property></bean><bean class="com.wenhai.spring.conversion.CustomizedPropertyEditorRegistrar"/></beans>
public class SpringCustomizedPropertyEditorDemo {public static void main(String[] args) {ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/property-editors-context.xml");User user = applicationContext.getBean("user", User.class);System.out.println(user);applicationContext.close();}}

Spring PropertyEditor 的设计缺陷

  • 违反单一职责:PropertyEditor 接口职责太多,除了类型转换,还包括 Java Beans 事件和 Java GUI 交互
  • PropertyEditor 实现类型局限:来源类型只能为 String 类型
  • PropertyEditor 实现缺少类型安全:除了实现类命名可以表达语义,实现类无法感知目标转换类型

Spring 3 通用类型转换接口

强依赖 JDK 5(支持泛型)

类型转换接口 :Converter<S,T>

  • 泛型参数 S:来源类型,参数 T:目标类型
  • 核心方法: T convert(S)

Converter 接口的局限性

  • 局限一:缺少 Source Type 和 Target Type 前置判断(使用 ConditionalConverter 解决)
  • 局限二:仅能转换单一的 Source Type 和 Target Type(使用 GenericConverter 解决)

通用类型转换接口:GenericConverter

  • 用于在两个或多个类型之间进行转换的泛型转换器接口。
  • 这是 Converter 中最灵活的SPI接口,也是最复杂的。它是灵活的,因为 GenericConverter 可以支持在多个源/目标类型对之间进行转换(参见 getConvertibleTypes() )。此外,在类型转换过程中,GenericConverter 实现可以访问源/目标字段上下文。这允许解析源字段和目标字段元数据,如注释和泛型信息,它们可用于影响转换逻辑。
  • 如果简单的 Converter 或 ConverterFactory 接口就足够了,通常不应该使用此接口。
  • 实现可以额外实现 ConditionalConverter。
  • 核心方法:convert(Object, TypeDescriptor, TypeDescriptor)
  • 配对类型:org.springframework.core.convert.converter.GenericConverter.ConvertiblePair
  • 类型描述:org.springframework.core.convert.TypeDescriptor
核心要素 说明
使用场景 用于 复合 类型转换场景,比如 Collection、Map、数组等
转换范围 Set<ConvertiblePair> getConvertibleTypes()
配对类型 GenericConverter.ConvertiblePair
转换方法 convert(Object, TypeDescriptor, TypeDescriptor)
类型描述 TypeDescriptor

GenericConverter 局限性

  • 缺少 Source Type 和 Target Type 前置判断
  • 单一类型转换实现复杂

优化接口:ConditionalGenericConverter

  • 复合类型转换:GenericConverter
  • 类型条件判断:ConditionalConverter

Spring 内建类型转换器

转换场景 实现类所在包名
日期/时间相关 org.springframework.format.datetime
Java 8 日期/时间相关 org.springframework.format.datetime.standard
通用实现 org.springframework.core.convert.support

扩展 Spring 类型转换器

  • 实现转换器接口

    • Converter
    • ConverterFactory
    • GenericConverter
  • 注册转换器实现
    • 通过 Spring Bean:ConversionServiceFactoryBean
    • 通过 API:ConversionService

统一类型转换服务

ConversionService

实现类型 说明
GenericConversionService 通用 ConversionService 模板实现,不内置转换器实现
DefaultConversionService 基础 ConversionService 实现,内置常用转换器实现
FormattingConversionService 通用 Formatter + GenericConversionService 实现,不内置转换器和 Formatter 实现
DefaultFomttingConversionService DefaultConversionService + 格式化实现(如:JSR-354 Money&Currency,JSR-310 Date-Time)

ConversionService 作为依赖

类型转换器底层接口:TypeConverter

定义类型转换方法的接口。通常(但不一定)与 PropertyEditorRegistry 接口一起实现。注意:因为 TypeConverter 的实现通常基于不是线程安全的 PropertyEditor,所以 TypeConverter 本身也不被认为是线程安全的。

  • 起始版本:spring 2.0
  • 核心方法:convertIfNecessary 重载方法
  • 抽象实现:TypeConverterSupport
  • 简单实现:SimpleTypeConverter

类型转换器底层抽象实现:TypeConverterSupport

所有方法实现都委派给 TypeConverterDelegate 的 TypeConverter 接口的基本实现。主要用作 BeanWrapperImpl 的基类。

  • 实现接口:TypeConverter
  • 扩展实现:PropertyEditorRegistrySupport
  • 委派实现:TypeConverterDelegate

类型转换器底层委派实现:TypeConverterDetegate

用于将属性值转换为目标类型的内部工具类。在给定的 PropertyEditorRegistrySupport 实例上工作。用作 BeanWrapperImpl 和SimpleTypeConverter 的委托。

  • 构造来源:AbstractNestablePropertyAccessor 实现(BeanWrapperImpl)
  • 依赖:PropertyEditor 实现(PropertyEditorRegistrySupport#registerDefaultEditors)
  • 可选依赖:ConversionService 实现

涉及接口/类

BeanMetadataElement

接口由携带配置源对象的 bean 元数据元素实现。

方法 作用
getSource() 返回当前元数据元素的配置源

AttributeAccessor

用于定义向任意对象附加元数据和从任意对象访问元数据的通用契约接口。

方法 作用
setAttribute(String, Object) 将name定义的属性设置为提供的值。如果value为空,则删除该属性。一般来说,用户应该注意使用完全限定名(可能使用类名或包名作为前缀)来防止与其他元数据属性的重叠
getAttribute(String) 获取按名称标识的属性的值。如果属性不存在,则返回 null
removeAttribute(String) 删除由name标识的属性并返回其值。如果name下没有找到属性,则返回null
hasAttribute(String) 如果以名称标识的属性存在,则返回 true。否则返回 false
arrtibuteName() 返回所有属性的名称

AttributeAccessorSupport

对 AttributeAccessor 提供所有方法的基本实现的支持类。子类可以进行扩展。

字段 作用
Map<String, Object> attributes = new LinkedHashMap() 存储属性
方法 作用
copyAttributesFrom(AttributeAccessor) 通过提供的 AttributeAccessor 复制属性到当前 AttributeAccessor

BeanMetadataAttribute

为 bean 定义(BeanDefinition)一部分的 key-value 样式属性的 Holder。跟踪除了 key-value 对之外的定义源。

字段 作用
Object source 存储元数据元素配置源
String name 属性名
Object value 属性值
方法 作用
BeanMetadataAttribute(String, Object) 构造器,创建一个新的 BeanMetadataAttribute 实例,属性名永远不能为 null,属性的值(可能在类型转换之前)
getName() 返回属性名
getValue() 返回属性值
setSource(Object) 为这个元数据元素设置配置源。对象的确切类型取决于所使用的配置机制

BeanMetadataAttributeAccessor

AttributeAccessorSupport 的扩展,将属性保存为 BeanMetadataAttribute 对象,以便跟踪定义源。

字段 作用
Object source 存储元数据元素配置源
方法 作用
setSource(Object) 为这个元数据元素设置配置源。对象的确切类型取决于所使用的配置机制
addMetadataAttribute(BeanMetadataAttribute) 将给定的 BeanMetadataAttribute 添加到该访问器的属性集
getMetadataAttribute(String) 在这个访问器的属性集中查找给定的 BeanMetadataAttribute

PropertyValue

用来保存单个 bean 属性的信息和值的对象。在这里使用一个对象,而不是仅仅存储所有属性在一个以属性名为键的映射中,允许更多的灵活性,并能够以一种优化的方式处理索引属性等。注意,值不需要是最终需要的类型:BeanWrapper实现应该处理任何必要的转换,因为这个对象不知道它将应用到的对象的任何信息。

字段 作用
String name 属性名
Object value 属性值
boolean optional 属性是否可选(默认是 false)
boolean converted 属性值是否已完成转换
Object convertedValue 属性值转换过的值
Beoolean conversionNecessary 指示是否需要转换
Object resolvedTokens 缓存已解析的属性路径标记
方法 作用
PropertyValue(String, Object) 创建一个新的 PropertyValue 实例。属性的名称(永远不可能为 null ),属性的值(可能在类型转换之前)
PropertyValue(PropertyValue) 拷贝构造器
PropertyValue(PropertyValue, Object) 为原始值持有者暴露新值的构造函数。原来的持有者将被作为新的持有者的来源
getName() 返回属性名
getValue() 返回属性值
getOOriginalPropertyValue() 返回此值持有者的原始PropertyValue实例
setOptional() 设置此值是否为可选值,即在目标类上不存在相应属性时忽略该值
isOptional() 返回是否为可选值,即当目标类上不存在相应属性时忽略该值
isConverted() 返回此持有者是否已经包含转换后的值(true),或该值是否仍需要转换(false)
setConvertedValue(Object) 在处理过的类型转换之后,设置此属性值的转换值
getConvertedValue() 在处理过的类型转换之后,返回此属性值的转换值

PropertyValues

包含一个或多个 PropertyValue 对象的 Holder,通常包含特定目标 bean 的一个更新。继承 Iterable<PropertyValue>

方法 作用
getPropertyValues() 返回保存在该对象中的PropertyValue对象的数组
getPropertyValue(String) 返回带有给定名称的属性值(如果有)
changesSince(PropertyValues) 返回自上一个PropertyValues以来的更改。子类也应该重写equals
contains(String) 此属性是否有属性值(或其他处理条目)
isEmpty() 不包含任何 PropertyValue 对象

MutablePropertyValues

PropertyValues 接口的默认实现。允许简单的属性操作,并提供构造函数来支持从 Map 深度复制和构造。

字段 作用
List<PropertyValue> propertyValueList PropertyValue 列表
Set<String> processedPropertyies 将指定的属性注册为 “processed”,即某些处理器在 PropertyValue 机制之外调用相应的setter方法。这将导致从指定属性的 contains(String)调用返回 true
boolean converted 将此 holder 标记为只包含转换后的值(即不再需要运行时解析)
方法 作用
MutablePropertyValues() 创建一个新的空MutablePropertyValues对象。属性值可以通过add方法添加
MutablePropertyValues(PropertyValues) 深拷贝构造函数。保证 PropertyValue 引用是独立的,尽管它不能深度复制单个 PropertyValue 对象当前引用的对象
MutablePropertyValues(Map<?,?>) 从Map中构造一个新的MutablePropertyValues对象
MutablePropertyValues(List<PropertyValues>) 使用给定的PropertyValue对象列表按原样构造一个新的MutablePropertyValues对象
getPropertyValueList() 以原始形式返回 PropertyValue 对象的基础List。返回的 List 可以直接修改,但不建议这样做
size() 返回列表中 PropertyValue 条目的数量
addPropertyValues(PropertyValues) 将所有给定的 PropertyValues 复制到此对象中。保证 PropertyValue 引用是独立的,尽管它不能深度复制单个 PropertyValue 对象当前引用的对象
addPropertyValues(Map<?,?>) 添加给定Map中的所有属性值
addPropertyValues(PropertyValue) 添加 PropertyValue 对象,替换对应属性的任何现有对象或与它合并(如果适用)
addPropertyValues(String, Object) addPropertyValue 的重载版本,它接受一个属性名和一个属性值。建议使用 add 方法
add(String, Object) 添加PropertyValue对象,替换对应属性的任何现有对象或与它合并(如果适用)
setPropertyValueAt(PropertyValue, int) 修改该对象中包含的PropertyValue对象。索引从0。
mergeIfRequired(PropertyValue, PropertyValue) 如果支持并启用合并,则将提供的 “new” PropertyValue 的值与当前 PropertyValue 的值合并
removePropertyValue(PropertyValue) 删除给定的PropertyValue(如果包含)
removePropertyValue(Stirng) 带有属性名的 removePropertyValue 的重载版本
get(String 获取原始属性值(如果有的话)
registerProcessedProperty(Stirng) 将指定的属性注册为 “processed” ,即某些处理器在 PropertyValue 机制之外调用相应的 setter 方法。这将导致从指定属性的 contains(String)调用返回 true
clearProcessedProperty(String) 清除给定属性的 “processed” 注册(如果有的话)
setConverted() 将此holder标记为只包含转换后的值
isConverted() 返回该持有者是否只包含转换后的值(true),或是否仍然需要转换值(false)

PropertyEditorRegistry

封装用于注册 JavaBean PropertyEditor 的方法。这是 PropertyEditorRegistrar 操作的中心接口。被 BeanWrapper 继承由BeanWrapperImpl 和 DataBinder 实现。

方法 作用
registerCustomEditor(Class<?>, PropertyEditor> ) 为所有给定类型的属性注册自定义属性编辑器
registerCustomEditor(Class<?>, String, PropertyEditor) 为给定类型的指定属性(如果为空,则是所有属性)注册自定义属性编辑器
findCustomEditor (Class<?>, String) 为给定类型和属性找到自定义属性编辑器。

PropertyEditorRegistrySupport

PropertyEditorRegistry 接口的基本实现。提供默认 PropertyEditor 和自定义 PropertyEditor 的管理。主要用作 BeanWrapperImpl 的基类。

字段 作用
ConversionService conversionService 指定一个用于转换属性值的 Convertionservice(Spring 3.0),作为 JavaBeans Propertyeditor 的替代方案
boolean defaultEditorsActive 是否激活此注册表实例的默认编辑器,允许在需要时延迟注册默认编辑器
boolean configValueEditorsActive 是否激活仅用于配置目的的配置值编辑器(StringArrayPropertyEditor)
Map<Class<?>, PropertyEditor> defaultEditors 默认属性的 PropertyEditor
Map<Class<?>, PropertyEditor> overriddenDefaultEditors 使用给定的属性编辑器覆盖指定类型的默认属性 PropertyEditor
Map<Class<?>, PropertyEditor> customEditors 存储指定类型的属性的 PropertyEditor
Map<String, CustomEditorHolder> customEditorsForPath 存储指定类型的指定属性的 PropertyEditor
Map<Class<?>, PropertyEditor> customEditorCache 缓存根据指定类型以及指定类型的子类型的 PropertyEditor
方法 作用
setConversionService(ConversionService) 指定一个用于转换属性值的 Convertionservice(Spring 3.0),作为 JavaBeans Propertyeditor 的替代方案
getConversionService() 返回关联的 ConversionService(如果有)
registerDefaultEditors() 激活此注册表实例的默认 PropertyEditor,允许在需要时延迟注册默认 PropertyEditor
useConfigValueEditors() 激活仅用于配置目的的配置值编辑器,例如 StringArrayPropertyEditor。这些编辑器默认情况下没有注册,因为它们通常不适合用于数据绑定目的。当然,在任何情况下都可以通过 registerCustomEditor(Class<?>, .PropertyEditor)
overrideDefaultEditor(Class<?>, PropertyEditor) 使用给定的属性编辑器覆盖指定类型的默认编辑器。请注意,这与注册自定义编辑器不同,因为编辑器在语义上仍然是默认编辑器。ConversionService 将覆盖这样的默认编辑器,而自定义编辑器通常覆盖 ConversionService
getDefaultEditor 检索给定属性类型的默认编辑器(如果有的话)。如果 默认编辑器是活动的(defaultEditorsActivetrue),则延迟注册它们
createDefaultEditors() 为这个注册表实例注册默认 PropertyEditor
copyDefaultEditorsTo(PropertyEditorSupport) 将此实例中注册的默认编辑器复制到给定的目标注册表
hasCutomEditorForElement(Class<?>, String) 确定此注册表是否包含指定数组/集合元素的自定义编辑器
getPropertyType(String) 确定给定属性路径的属性类型。被 findCustomEditor (Class <?>,String) 调用,即使没有指定所需的类型,只给出属性路径,也能够找到特定类型的编辑器。默认实现总是返回 null。BeanWrapperImpl 用 BeanWrapper 接口定义的标准 getPropertyType 方法覆盖了这个
getCustomEditor(String, Class<?>) 获取已为给定属性注册的自定义编辑器
getCustomEditor(Class<?>) 获取给定类型的自定义编辑器。如果直接匹配没有找到,尝试自定义编辑器超类(在任何情况下,它将能够通过 getAsText 呈现一个值为 String)
guessPropertyTypeFromEditor(String) 从已注册的自定义编辑器中猜测指定属性的属性类型(假设它们已注册为特定类型)
copyCustomEditorsTo(PropertyEditorRegistry, String 将在此实例中注册的自定义编辑器复制到给定的目标注册表
addStrippedPropertyPaths(List<String>, String, String) 添加带有剥离键和/或索引的所有变体的属性路径。使用嵌套路径递归地调用自身

PropertyEditorRegistrar

用于向 PropertyEditorRegistry 注册自定义 PropertyEditor 策略的接口。当你需要在几种不同的情况下使用同一组属性编辑器时,这特别有用(编写相应的注册器并在每种情况下重用它)

方法 作用
registerCustomEditors(PropertyEditorRegistry) 为所有给定类型的属性注册自定义属性编辑器。传入的 PropertyEditorRegistry 通常是 BeanWrapper 或 DataBinder。预计实现将为这个方法的每次调用创建全新的 Propertyedito r实例(因为 Propertyeditor 不是线程安全的)

PropertyEditorRegistrar 内建实现

实现类型 说明
ResourceEditorRegistrar 用默认注册的资源类型的编辑器(Resource、ContextResource、InputStream、InputSource、File 等等)填充给定的 PropertyEditorRegistry (通常是用于在 ApplicationContext 中创建 bean 的 BeanWrapper),由 AbstractApplicationContext 使用 。

PropertyAccessor

可以访问命名属性(如对象的 bean 属性或对象中的字段)的类的公共接口用作 BeanWrapper 的基接口。

方法 作用
isReadableProperty(String) 确定指定的属性是否可读。如果属性不存在,则返回 false
isWrittableProperty(String) 确定指定的属性是否可写。如果属性不存在,则返回 false
getPropertyType(String) 确定指定的属性的属性类型。检查属性描述符或检查索引或映射元素的值
getPropertyTypeDescriptor(String) 返回指定属性的类型描述符
getPropertyValue(String) 获取指定属性的当前值
setPropertyValue(String, Object) 设置指定属性的当前值
setPropertyValue(PropertyValue) 设置指定属性的当前值
setPropertyValues(Map<?,?)) 从 Map 执行批量更新。来自 PropertyValues 的批量更新功能更强大:提供此方法是为了方便。行为将与 setPropertyValues(PropertyValues) 方法相同
setPropertyValues(PropertyValues) 执行批处理更新的首选方法。注意:执行批量更新与执行一个更新,在这个类的实现将继续更新属性如果可恢复错误(如类型不匹配,而不是一个无效的字段名或类似的),遇到扔 PropertyBatchUpdateException包含所有个人的错误。稍后可以检查此异常以查看所有绑定错误。已成功更新的属性仍然更改。不允许未知字段或无效字段
setPropertyValues(PropertyValues, boolean) 执行批处理更新,对行为进行更多控制。允许未知字段,不允许无效字段
setPropertyValues(PropertyValues, boolean, boolean) 执行批处理更新,对行为进行更多控制。允许未知字段和无效字段

ConfigurablePropertyAccessor

封装 PropertyAccessor 的配置方法的接口。还扩展了 PropertyEditorRegistry 接口,该接口定义了PropertyEditor 管理的方法。作为 BeanWrapper 的基本接口。

方法 作用
setConversionService(ConversionService) 指定一个用于转换属性值的 ConversionService(Spring 3.0) ,作为 JavaBeans PropertyEditor 的替代方案
getConversionService() 返回关联的 ConversionService(如果有的话)
setExtractOldValueForEditor(boolean) 设置在将属性编辑器应用于属性的新值时是否提取旧属性值
isExtractOldValueForEditor() 返回在将属性编辑器应用于属性的新值时是否提取旧属性值
setAutoGrowNestedPaths(boolean) 设置此实例是否应该尝试自动增长包含空值的嵌套路径。如果为 truenull 路径位置将使用默认对象值填充并遍历,而不是导致 NullValueInNestedPathException。在普通的 PropertyAccessor 实例上,默认值为false
isAutoGrowNestedPaths() 返回是否已激活嵌套路径的自动增长

AbstractPropertyAccessor

PropertyAccessor接口的抽象实现。提供所有便利方法的基本实现,实际属性访问的实现留给子类。

字段 作用
boolean extractOldValueForEditor 将属性编辑器应用于属性的新值时是否提取旧属性值,默认值为 false
boolean autoGrowNestedPaths 设置此实例是否应该尝试“自动增长”包含空值的嵌套路径。如果为 true,空路径位置将使用默认对象值填充并遍历,而不是导致 NullValueInNestedPathException。在普通的 PropertyAccessor 实例上,默认值为 false

AbstractNestablePropertyAccessor

一个基本的 ConfigurablePropertyAccessor,它为所有典型用例提供了必要的基础设施。
如果需要,该访问器将把集合和数组值转换为相应的目标集合或数组。处理集合或数组的自定义属性编辑器既可以通过 PropertyEdito r的s etValue 编写,也可以通过 setAsText 编写以逗号分隔的字符串,因为如果数组本身是不可分配的,字符串数组将以这种格式转换。

字段 作用
int autoGrowCollectionLimit = Integer.MAX_VALUE 数组和集合自动增长限制
Object wrappedObject 包装的 bean 实例对象
String nestedPath 嵌套路径
Object rootObject 路径根对象
Map<String, AbstractNestablePropertyAccessor> nestedPropertyAccessors 映射缓存的嵌套访问器:嵌套路径->访问器实例
方法 作用
AbstractNestablePropertyAccessor() 创建一个新的空访问器。包装的实例需要在之后设置。注册默认编辑器
AbstractNestablePropertyAccessor(boolean) 创建一个新的空访问器。包装的实例需要在之后设置。是否注册默认编辑器
AbstractNestablePropertyAccessor(Object) 为给定对象创建一个新的访问器并注册默认编辑器
AbstractNestablePropertyAccessor(Class<?>) 创建一个新的访问器,包装指定类的新实例并注册默认编辑器
AbstractNestablePropertyAccessor(Object, String, Object) 为给定对象创建一个新的访问器,注册对象所在的嵌套路径并注册默认编辑器
AbstractNestablePropertyAccessor(Object, String, AbstractNestablePropertyAccessor) 为给定对象创建一个新的访问器,注册对象所在的嵌套路径
setAutoGrowCollectionLimit(int) 为数组和集合自动增长指定限制。默认值在普通访问器上是无限的
getAutoGrowCollectionLimit() 返回数组和集合自动增长的限制
setWrappedInstance(Object) 切换目标对象,只有当新对象的类与被替换对象的类不同时,才会替换缓存的内省结果
setWrappedInstance(Object, String, Object) 切换目标对象,只有当新对象的类与被替换对象的类不同时,才会替换缓存的内省结果
getNestedPaht() 返回由此访问器包装的对象的嵌套路径
getRootInstance() 返回此访问器路径的根对象
getRootClass() 返回此访问器路径的根对象的类型
getFinalPath(AbstractNestablePropertyAccessor, String) 获取路径的最后一个组件。如果没有嵌套,也可以工作

BeanWrapper

  • Spring 底层 JavaBeans 基础设施的中心接口。
  • 通常不是直接使用,而是通过 BeanFactory 或Databinder 隐式使用。
  • 提供分析和操作标准 JavaBeans 的操作:能够获取和设置属性值(单独或批量),获取属性描述符,以及查询属性的可读性/可写性。
  • 该接口支持嵌套属性,允许对子属性进行无限深度的属性设置。
  • BeanWrapper默认的 extractOldValueForEditor 设置是 false,以避免 getter 方法调用引起的副作用。将此转换为 true 以向自定义编辑器暴露当前的属性值。
方法 作用
setAutoGrowCollectionLimit(int) 为数组和集合自动增长指定限制。在普通BeanWrapper上,默认值是无限的
getAutoGrowCollectionLimit() 返回数组和集合自动增长的限制
getWrapperInstance() 返回由该对象包装的bean实例
getWrappedClass() 返回包装bean实例的类型
getPropertyDescriptors() 获取包装对象的PropertyDescriptors(由标准JavaBeans自省决定)
getPropertyDescriptor(String) 获取包装对象的特定属性的属性描述符。

BeanWrapperImpl

  • 默认的 BeanWrapper 实现应该足以满足所有典型的用例。缓存内省结果以提高效率。
  • 注意:除了应用于 JDK 的标准 PropertyEditor,还自动注册 org.springframework.beans.propertyeditors 包中的默认属性编辑器。应用程序可以调用 PropertyEditorRegistrySupport#registerCustomEditor(PropertyEditor)方法来为特定实例注册编辑器(即它们不是跨应用程序共享的)。
  • 注意:在 Spring 2.5 中,这几乎是一个内部类。它是公共的,以便允许从其他框架包访问。对于标准的应用程序访问目的,使用 PropertyAccessorFactory.forBeanPropertyAccess(Object) 工厂方法代替。

类型转换流程图

跟着小马哥学系列之 Spring IoC(进阶篇:类型转换)相关推荐

  1. 跟着小马哥学系列之 Spring IoC(源码篇:Bean 生命周期)

    跟着小马哥学系列之 Spring IoC(源码篇:Bean 生命周期) 简介 Bean 元信息来源 Bean 元信息解析成 BeanDefinition 并注册 BeanDefinition 转变成 ...

  2. 跟着小马哥学系列之 Spring IoC(源码篇:@Import)

    跟着小马哥学系列之 Spring IoC(源码篇:@Import) 简介 @ Import 简介 元信息 元注解 属性 @Import 注解 value 属性取值范围 ImportSelector I ...

  3. 跟着小马哥学系列之 Spring IoC(进阶篇:Environment)

    学成路更宽,吊打面试官. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...

  4. 跟着小马哥学系列之 Spring AOP(Pointcut 组件详解)

    学好路更宽,钱多少加班. --小马哥 版本修订 2021.5.19:去除目录 2021.5.21:引用 Spring 官方 Pointcut 概念,修改 Pointcut 功能表述 简介 大家好,我是 ...

  5. 跟着小马哥学系列之 Spring AOP(Advisor 详解)

    学好路更宽,钱多少加班. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...

  6. 跟着小马哥学系列之 Spring AOP(AbstractAutoProxyCreator 详解)

    学成路更宽,吊打面试官. --小马哥 版本修订 2021.5.19:去除目录 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了 ...

  7. 跟着小马哥学系列之 Spring AOP(基于 XML 定义 Advice 源码解析)

    学好路更宽,钱多少加班. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...

  8. 源码深度解析系列之 Spring IOC

    大家好,我是黎杜,今天和大家聊聊Spring IOC的源码! 历时 4 个多月,终于把 Sping 源码系列写完了,该系列一共 5 篇,后续会整理成 PDF 教程,本文是最后一篇. 这篇文章主要讲解 ...

  9. Axure设计html,从零开始学Axure原型设计(进阶篇)_html/css_WEB-ITnose

    从零开始学Axure原型设计(进阶篇) Axure不仅能制作静态的视觉稿.页面,还能添加交互动作,是进行原型设计的最佳软件之一.在认识了Axure的界面和部件库之后,我们可以用它来画线框图了,但是静态 ...

最新文章

  1. java课设推荐,《Java程序设计》课程设计报告推荐.docx
  2. 嵌入式linux硬件成本,嵌入式Linux驱动和固件有何区别?供应商是如何用固件压缩成本的?...
  3. python 利用pyttsx3文字转语音
  4. AES加密,加签验签
  5. linux读取.data文件,[20121227]v$datafile访问是从数据文件获取信息吗.txt
  6. 原来国家的名字可以如此的浪漫~~!
  7. c语言作业题整理,C语言考试模拟练习题
  8. 使用实体框架或C#中的任何IEnumerable列出批处理/分页
  9. Arcgis Android API开发之离线地图
  10. ASAv的qcow2镜像文件添加ASDM
  11. python tkinter:单位换算小工具完整代码
  12. 找出不大于n的最大质数
  13. win10安装navisworks失败,怎么强力卸载删除注册表并重新安装
  14. Octet string 解析
  15. 直播视频流+html,前端页面播放 rtmp 流与 flv 格式视频文件
  16. 转:我,喜,欢,你,很久了……
  17. matlab 怎么使用mathtype,教你怎样在Authorea里面使用MathType
  18. useNavigate使用报错
  19. oracle数据库方案模式,Oracle数据库技术服务方案.doc
  20. bach cello

热门文章

  1. 第十一届蓝桥杯——JAVA组真题
  2. python爬取豆瓣电影信息_Python|简单爬取豆瓣网电影信息
  3. Allegro如何输出第三方网表操作指导
  4. Trying to access array offset on value of type null
  5. Python用Tkinter实现日期计算器
  6. android数据回传多个页面_Android-Activity之间回传数据
  7. Linux图形系统框架 与 X协议 X11 XFree86 Xorg X-Window WM
  8. ubuntu篇---ubuntu安装mysql教程
  9. 香侬科技GNN-LM:基于全局信息的图神经网络语义理解模型笔记
  10. layui多文件上传讲解_Laravel 使用 layui 文件上传组件批量上传图片