anyeeye 发表于 2013-2-3 14:02:06

关于Spring属性编辑器详解

最近刚在研究Spring的编辑器,发现很有意思,刚好galaxystar起了一个这样贴,我想对PropertyEditor作一个详细的整理会对大家有益,特定启了这个新帖。

所谓的PropertyEditor,顾名思义,就是属性编辑器。由于Bean属性通过配置文档以字符串了方式为属性赋值,所以必须有一个“东东”负责将这个字符串转换为属性的直接对象,如属性的类型为int,那么编辑器要做的工作就是int i = Integer.parseInt("1");
Spring为一般的属性类型提供了默认的编辑器,BeanWrapperImpl是Spring框架中重要的类,它负责对注入的Bean进行包装化的管理,常见属性类型对应的编辑器即在该类中通过以下代码定义:



代码
private void registerDefaultEditors()   
    {   
      // Simple editors, without parameterization capabilities.   
      // The JDK does not contain a default editor for any of these target types.   
      this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());   
      this.defaultEditors.put(Class.class, new ClassEditor());   
      this.defaultEditors.put(File.class, new FileEditor());   
      this.defaultEditors.put(InputStream.class, new InputStreamEditor());   
      this.defaultEditors.put(Locale.class, new LocaleEditor());   
      this.defaultEditors.put(Properties.class, new PropertiesEditor());   
      this.defaultEditors.put(Resource[].class,   
                              new ResourceArrayPropertyEditor());   
      this.defaultEditors.put(String[].class, new StringArrayPropertyEditor());   
      this.defaultEditors.put(URL.class, new URLEditor());   

      // Default instances of collection editors.   
      // Can be overridden by registering custom instances of those as custom editors.   
      this.defaultEditors.put(Collection.class,   
                              new CustomCollectionEditor(Collection.class));   
      this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));   
      this.defaultEditors.put(SortedSet.class,   
                              new CustomCollectionEditor(SortedSet.class));   
      this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));   

      // Default instances of character and boolean editors.   
      // Can be overridden by registering custom instances of those as custom editors.   
      PropertyEditor characterEditor = new CharacterEditor(false);   
      PropertyEditor booleanEditor = new CustomBooleanEditor(false);   

      // The JDK does not contain a default editor for char!   
      this.defaultEditors.put(char.class, characterEditor);   
      this.defaultEditors.put(Character.class, characterEditor);   

      // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.   
      this.defaultEditors.put(boolean.class, booleanEditor);   
      this.defaultEditors.put(Boolean.class, booleanEditor);   

      // The JDK does not contain default editors for number wrapper types!   
      // Override JDK primitive number editors with our own CustomNumberEditor.   
      PropertyEditor byteEditor = new CustomNumberEditor(Byte.class, false);   
      PropertyEditor shortEditor = new CustomNumberEditor(Short.class, false);   
      PropertyEditor integerEditor = new CustomNumberEditor(Integer.class, false);   
      PropertyEditor longEditor = new CustomNumberEditor(Long.class, false);   
      PropertyEditor floatEditor = new CustomNumberEditor(Float.class, false);   
      PropertyEditor doubleEditor = new CustomNumberEditor(Double.class, false);   

      this.defaultEditors.put(byte.class, byteEditor);   
      this.defaultEditors.put(Byte.class, byteEditor);   

      this.defaultEditors.put(short.class, shortEditor);   
      this.defaultEditors.put(Short.class, shortEditor);   

      this.defaultEditors.put(int.class, integerEditor);   
      this.defaultEditors.put(Integer.class, integerEditor);   

      this.defaultEditors.put(long.class, longEditor);   
      this.defaultEditors.put(Long.class, longEditor);   

      this.defaultEditors.put(float.class, floatEditor);   
      this.defaultEditors.put(Float.class, floatEditor);   

      this.defaultEditors.put(double.class, doubleEditor);   
      this.defaultEditors.put(Double.class, doubleEditor);   

      this.defaultEditors.put(BigDecimal.class,   
                              new CustomNumberEditor(BigDecimal.class, false));   
      this.defaultEditors.put(BigInteger.class,   
                              new CustomNumberEditor(BigInteger.class, false));   
    }   


但是,并非Bean的属性都是这些常见的类型,如果你的Bean需要注入一个自定义类型的属性,而又想享受IoC的好处,那么就只得自己开干,提供一个自定义的PropertyEditor了。
下面,分几个步骤来说明,定义一个自定义PropertyEditor的过程。
1)首先,碰到的问题即是,要如何编辑自己的PropertyEditor,其实需要了解一点java.beans包的知识,在该包中,有一个java.beans.PropertyEditor的接口,它定义了一套接口方法(12个),即通过这些方法如何将一个String变成内部的一个对象,这两个方法是比较重要的:
a)setValue(Object value) 直接设置一个对象,一般不直接用该方法设置属性对象
b)setAsText(String text) 通过一个字符串来构造对象,一般在此方法中解析字符串,将构造一个
类对象,调用setValue(Object)来完成属性对象设置操作。

2)实现所有的接口方法是麻烦的,java.beans.PropertyEditorSupport 适时登场,一般情况下,我们通过扩展这个方便类即可。

3)编写完后,就是在Spring配置文件中注册该属性类型编辑器的问题,Spring提供了专门的注册工具类
org.springframework.beans.factory.config.CustomEditorConfigurer,它负责将属性类型和
属性编辑器关联起来。到时BeanFactory注入Bean的属性时,即会在注册表中查找属性类型对应的编辑器。

下面给出一个小例子,例子先作一个简单描述:
1)Person 需要进行属性注入的Bean,有两个属性 一个是name,一个是address Address是一个类
2)Address Person的属性类型,本身有3个属性。
3)AddressPropertyEditor Address类型对应的属性编辑器。

开工:
1.Person.java


代码
package com.stamen.propedit;   

import org.apache.commons.lang.builder.ToStringBuilder;   

public class Person {   
    private String name;   

    private Address address;   

    public Address getAddress() {   
      return address;   
    }   

    public void setAddress(Address address) {   
      this.address = address;   
    }   

    public String getName() {   
      return name;   
    }   

    public void setName(String name) {   
      this.name = name;   
    }   
    public String toString() {   
      return ToStringBuilder.reflectionToString(this);   
    }   
}   



2.Address.java

代码
package com.stamen.propedit;   
import org.apache.commons.lang.builder.ToStringBuilder;   
public class Address {   
    private String street;   

    private String doorNum;   

    private String postCode;   

    public String getDoorNum() {   
      return doorNum;   
    }   

    public void setDoorNum(String doorNum) {   
      this.doorNum = doorNum;   
    }   

    public String getPostCode() {   
      return postCode;   
    }   

    public void setPostCode(String postCode) {   
      this.postCode = postCode;   
    }   

    public String getStreet() {   
      return street;   
    }   

    public void setStreet(String street) {   
      this.street = street;   
    }   
      
    public String toString() {   
      return ToStringBuilder.reflectionToString(this);   
    }   

}   
   



AddressPropertyEditor.java

代码
package com.stamen.propedit;   

import java.beans.PropertyEditorSupport;   
import java.util.Date;   

import org.springframework.util.StringUtils;   
public class AddressPropertyEditor extends PropertyEditorSupport{   
    //支持的格式为 streeValue,doorNumValue,postCode   
    public void setAsText(String text)   
    {   
      System.out.println("使用自己的编辑器。");   
      if (text == null || !StringUtils.hasText(text)) {   
            throw new IllegalArgumentException("老大,不能为空啊!");   
      }   
      else
      {   
            String[] strArr = StringUtils.tokenizeToStringArray(text,",");   
            Address add = new Address();   
            add.setStreet(strArr);   
            add.setDoorNum(strArr);   
            add.setPostCode(strArr);   
            setValue(add);   
      }   
    }   
      
    public String getAsText()   
    {   
      Address add = (Address)getValue();   
      return ""+add;   
    }   
}   
   


打开Spring配置文件,添上这两个配置项:


代码
<bean id="customEditorConfigurer"class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
    <map>
      <entry key="com.stamen.propedit.Address"> <!-- 属性类型 -->
      <bean class="com.stamen.propedit.AddressPropertyEditor"/> <!--对应Address的编辑器 -->
      </entry>
    </map>
</property>
</bean>

<bean id="person" class="com.stamen.propedit.Person">
    <property name="name" value="Tom"/>
    <property name="address" value="朝阳区,Soho 1601,010101"/>
</bean>
页: [1]
查看完整版本: 关于Spring属性编辑器详解