接口定义
// Spring低级JavaBeans基础设施的中央接口。通常来说并不直接使用BeanWrapper,而是借助BeanFactory或者DataBinder来一起使用,BeanWrapper对Spring中的Bean做了包装,为的是更加方便的操作Bean中的属性 public interface BeanWrapper extends ConfigurablePropertyAccessor { void setAutoGrowCollectionLimit(int autoGrowCollectionLimit); int getAutoGrowCollectionLimit(); // 获取包装的Bean Object getWrappedInstance(); // 获取包装的Bean的class Class<?> getWrappedClass(); // 获取所有属性的属性描述符 PropertyDescriptor[] getPropertyDescriptors(); // 获取指定属性的属性描述符 PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException; }
这里需要解释一个概念,什么是属性描述符?
PropertyDescriptor:属性描述符,能够描述javaBean中的属性,通过属性描述符我们能知道这个属性的类型,获取到操纵属性的方法(getter/setter)
继承关系
BeanWrapper的子类只有一个:BeanWrapperImpl,它继承了ConfigurablePropertyAccessor,这个接口的主要功能是进行属性访问,同时它又有三个父接口,接下来我们一一分析他们的功能。
接口功能
1、PropertyEditorRegistry(属性编辑器注册器)
接口定义
// 这个接口的功能很简单,就是用来注入属性编辑器(PropertyEditor),那么什么是PropertyEditor呢? public interface PropertyEditorRegistry { void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor); void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor); @Nullable PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath); }
PropertyEditor
概念
PropertyEditor是JavaBean规范定义的接口,这是java.beans中一个接口,其设计的意图是图形化编程上,方便对象与String之间的转换工作,而Spring将其扩展,方便各种对象与String之间的转换工作。
Spring中对PropertyEditor使用的实例
1.我们在通过XML的方式对Spring中的Bean进行配置时,不管Bean中的属性是何种类型,都是直接通过字面值来设置Bean中的属性。那么是什么在这其中做转换呢?这里用到的就是PropertyEditor
2.SpringMVC在解析请求参数时,也是使用的PropertyEditor
Spring内置的PropertyEditor
2、PropertyAccessor(属性访问器)
接口定义
public interface PropertyAccessor { // 嵌套属性的分隔符,比如"foo.bar"将会调用getFoo().getBar()两个方法 String NESTED_PROPERTY_SEPARATOR = "."; char NESTED_PROPERTY_SEPARATOR_CHAR = '.'; // 代表角标index的符号 如person.addresses[0] 这样就可以把值放进集合/数组/Map里了 String PROPERTY_KEY_PREFIX = "["; char PROPERTY_KEY_PREFIX_CHAR = '['; String PROPERTY_KEY_SUFFIX = "]"; char PROPERTY_KEY_SUFFIX_CHAR = ']'; // 该属性是否可读/可写,不存在则返回false boolean isReadableProperty(String propertyName); boolean isWritableProperty(String propertyName); // 获取/设置属性的方法,基本见名知意 @Nullable Class<?> getPropertyType(String propertyName) throws BeansException; @Nullable TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException; @Nullable Object getPropertyValue(String propertyName) throws BeansException; void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException; void setPropertyValue(PropertyValue pv) throws BeansException; void setPropertyValues(Map<?, ?> map) throws BeansException; void setPropertyValues(PropertyValues pvs) throws BeansException; void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown) throws BeansException; void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) throws BeansException; }
这里需要解释一个概念,什么是PropertyValue?
当设置属性值时,少不了两样东西:
1.属性访问表达式:如listMap[0][0]
2.属性值:
ProperyValue对象就是用来封装这些信息的。如果某个值要给赋值给bean属性,Spring都会把这个值包装成ProperyValue对象。
3、TypeConverter(类型转换器)
接口定义
// 定义了进行类型转换时的一些规范,就像名字定义的那样,主要用来做类型转换 public interface TypeConverter { // 将指定的值转换成指定的类型 @Nullable <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException; // 相对于上面这个方法下面这个三种方法能处理转换过程中的泛型 @Nullable <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException; @Nullable <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field) throws TypeMismatchException; default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException { throw new UnsupportedOperationException("TypeDescriptor resolution not supported"); } }
4、ConfigurablePropertyAccessor
public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter { // ConversionService:进行转换的业务类,转换系统的入口 void setConversionService(@Nullable ConversionService conversionService); @Nullable ConversionService getConversionService(); // 进行属性编辑是是否返回旧的值 void setExtractOldValueForEditor(boolean extractOldValueForEditor); boolean isExtractOldValueForEditor(); // 当设置(dog.name)这种嵌套属性的情况下,如果dog属性为null是否会报错 // 为true的话不会,为false会抛出NullValueInNestedPathException void setAutoGrowNestedPaths(boolean autoGrowNestedPaths); boolean isAutoGrowNestedPaths(); }
从上面可以看到,BeanWrapper接口自身对Bean进行了一层包装。另外它的几个通过间接继承了几个接口,所以它还能对Bean中的属性进行操作。PropertyAccessor赋予了BeanWrapper对属性进行访问及设置的能力,在对Bean中属性进行设置时,不可避免的需要对类型进行转换,而恰好PropertyEditorRegistry,TypeConverter就提供了类型转换的统一约束。
在了解了接口之后,我们接下来看看它的唯一实现类BeanWrapperImpl