说说 Spring 的属性编辑器

综合编程 2018-05-18 阅读原文

在 Spring 配置文件中,我们往往通过字面值设置 Bean 各种类型的属性值 ,这个功能是通过属性编辑器实现的。

任何实现了 java.beans.PropertyEditor 接口的类都是属性编辑器 。 它可以将外部需要设置的值转换为 JVM 内部的对应类型,所以属性编辑器其实就是一个类型转换器 。

1 JavaBean 编辑器

Sun 所制定的 JavaBean 编辑器,很大程度上是为 IDE 准备的。它让 IDE 能够以可视化的方式来设置 JavaBean 的属性 。

Java 通过 java.beans.PropertyEditor 定义了设置 JavaBean 属性的方法,通过 BeanInfo 描述了 JavaBean 哪些属性是可定制的,此外还描述了可定制属性与 PropertyEditor 之间的对应关系 。

BeanInfo 与 JavaBean 之间的对应关系,通过两者之间规范的命名确立,对应 JavaBean 的 BeanInfo 采用如下命名规范: BeanInfo
。 如 BookBean 对应的 BeanInfo 为 BookBeanBeanInfo。 当 JavaBean 连同其属性编辑器注册到 IDE 后,当在开发界面中对 JavaBean 进行定制时, IDE 就会根据 JavaBean 规范找到对应的 BeanInfo ,然后再根据 BeanInfo 中的描述信息找到 JavaBean 属性描述(使用哪个属性编辑器等),进而为 JavaBean 生成特定开发编辑界面 。

Java 提供了一个用于管理默认属性编辑器的管理器: PropertyEditorManager ,它保存着一些常见类型的属性编辑器,如果某个 JavaBean 的常见类型属性没有通过 BeanInfo 显式指定它的属性编辑器, 那么 IDE 将自动使用 PropertyEditorManager 中注册的对应属性的默认编辑器 。

1.1 属性编辑器(PropertyEditor)

PropertyEditor 是属性编辑器接口,它定义了将外部设置值转换为内部 JavaBean 属性值的接口方法 。主要接口方法说明如下:

方法说明
Object getValue()返回属性的当前值 ,基本类型被封装成对应的包装类型
void setValue(Object newValue)设置属性的值,基本类型以包装类型传入
String getAsText()用字符串来表示属性对象,以便外部的属性编辑器能够以可视化的方式显示 。 默认返回 null ,表示该属性不能以字符串表示。
void setAsText(String text)用一个字符串去更新属性的内部值,它一般从外部属性编辑器传入的。
String[] getTags()返回表示有效属性值的字符串数组,以便属性编辑器能够以下拉框的方式进行展示 。 默认返回 null。
String getJavaInitializationString()为属性提供初始值,属性编辑器以此值作为属性的默认值 。

PropertyEditor 接口是内部属性值和外部设置值的沟通桥梁 。

Java 为 PropertyEditor 提供了一个方便的实现类: PropertyEditorSupport ,该类实现了 PropertyEditor 接口,我们可以通过扩展这个类来设计自己的属性编辑器 。

1.2 Bean 属性描述(BeanInfo)

BeanInfo 描述了 JavaBean 中的可编辑属性以及对应的属性编辑器,每一个属性对应一个属性描述器 PropertyDescriptor。

PropertyDescriptor 的构造函数有两个入参: PropertyDescriptor(String propertyName, Class beanClass)
,其中 propertyName 为属性名; beanClass 是 JavaBean 所对应的 Class。

PropertyDescriptor 还有一个 setPropertyEditorClass(Class propertyEditorClass) 方法,它可以为 JavaBean 属性指定编辑器 。

BeanInfo 接口中最重要的方法是: PropertyDescriptor[] getPropertyDescriptors()
,它会返回 JavaBean 的属性描述器数组 。

BeanInfo 接口的一个常用的实现类是 SimpleBeanInfo ,我们可以通过扩展这个类来实现自定义的功能 。

2 Spring 默认属性编辑器

Spring 的属性编辑器与传统的用于 IDE 开发的属性编辑器不同,它没有 UI 界面,只是将配置文件中的文本配置值转换为 Bean 属性的对应值 。

Spring 在 PropertyEditorRegistrySupport 中为常见的属性类型提供了默认属性编辑器,分为 3 大类,共有 32 个:

类型说明
基础数据类型【1】基本数据类型,如: boolean、int 等; 【2】基本数据类型封装类,如: Boolean、Integer 等; 【3】基本数据类型数组: char[] 和 byte[] ; 【4】大数: BigDecimal 和 BigInteger 。
集合类Collection、Set、SortedSet、List 和 SortedMap。
资源类Class、Class[]、File、InputStream、Locale、Properties、Resource[] 和 URL。

PropertyEditorRegistrySupport 中有两个用于保存属性编辑器的 Map 类型变量:

变量名说明
defaultEditors保存默认属性类型的编辑器,元素的键为属性类型,值为对应的属性编辑器实例。
customEditors保存用户自定义的属性编辑器,元素的键值和 defaultEditors 相同 。

3 自定义 Spring 属性编辑器

如果我们的应用定义了特殊类型的属性,并且希望在配置文件中以字面值方式来配置属性值,那么就可以编写自定义属性编辑器并注册到 Spring 容器的方式来实现。

Spring 默认的属性编辑器大都扩展自 java.beans.PropertyEditorSupport
,我们可以通过扩展 PropertyEditorSupport 来自定义属性编辑器 。在Spring 环境下仅需要将配置文件中字面值转换为属性类型的对象即可,并不需要提供 UI 界面,所以仅需要覆盖 PropertyEditorSupport 的 setAsText() 方法就可以啦 (∩_∩)O哈哈~。

假设我们有两个实体 Book 和 Author,希望在配置 Book 时,可以直接设置 Author 的名字。

Book.java

public class Book {

    /**
     * 作者
     */
    private Author author;


    /**
     * 书名
     */
    private String name;
  //省略 get/setter 方法
}

Author.java

public class Author {

    private String name;
   //省略 get/setter 方法
}

首先,自定义 author 的属性编辑器:

public class CustomPropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if(text==null||text.length()==0){
            throw new IllegalArgumentException("格式错误");
        }

        Author author=new Author();
        author.setName(text);

        //调用父类的方法,来设置属性对象
        setValue(author);
    }
}

如果使用 BeanFactory ,则需要手工调用 registerCustomEditor(Class requiredType, PropertyEditor propertyEditor)
方法注册自定义属性编辑器;如果使用的是 ApplicationContext ,那么只需要在配置文件中注册 CustomEditorConfigurer 即可 。CustomEditorConfigurer 实现了BeanFactoryPostProcessor 接口,所以它是一个 Bean 的工厂后处理器 。

现在注册自定义的属性编辑器:


    
        
            
            
        
    



    
    
    

BeanWrapper 在设置 book 的 author 属性时,将检索自定义属性编辑器注册表,当发现 author 属性类型所对应的属性编辑器 CustomPropertyEditor 时,它就会这个定制的属性编辑器把 "村上春树" 转换为 Author 对象 。

按照规范, Java 会在 JavaBean 的相同类包下查找是否存在 Editor
的类;如果存在,就会自动使用 Editor
作为该 JavaBean 的属性编辑器 。Spring 也支持这个规范。

所以如果在类包下有一个名为 AuthorEditor 属性编辑器类,那么就无须在配置文件中注册自定义的属性编辑器啦O(∩_∩)O哈哈~

简书

责编内容by:简书阅读原文】。感谢您的支持!

您可能感兴趣的

码云推荐 | 轻量快速的对象池 Lite-pool 内容索引(Table of Contents) 1. Lite-pool 1.1. 简介 Lite-pool : 轻量快速的对象池 1.2. 安装前置条件 jdk 1.8+ maven-3...
GNU Toolchain Update – Spring 2018 The GNU Toolchain is a collection of programming tools produced by the GNU Project. The tools are often packaged toge...
Spring Framework 5.0 RC2 发布 Spring Framework 5.0 RC2 版本中正式将非空声明的 API 加入到标准包内,依照 JSR305 规范标准,可在注解内显示声明可空参数和返回值,在现有版本的 IntelliJ IDEA 和未来版本的 Kotlin 里都会...
PCF 2.0 Expands Platform to Include Containers and... Pivotal Cloud Foundry (PCF) version 2.0 sees a significant expansion of the platform. As well as the original Platform a...
spring aop 日志拦截器的实现(原创) spring aop 日志拦截器的实现(原创) 利用 spring aop 的 around 来实现日志拦截器,此拦截器负责打印抛出到顶层的异常日志。 具体实现 引入相关切面依赖 org...