PropertyEditor和Converter有什么区别

 

PropertyEditor自定义实现

在上一章节对数据绑定底层做了详细分析,其中就对提到数据绑定就是基于PropertyEditor作为数据转换的工具来实现绑定关系的协调作用,本章将对PropertyEditor注册以及结合Spring如何自定义PropertyEditor。

PropertyEditor注册

首先回到IDEA手,首先我们回到PropertyEditor接口找到他的子类PropertyEditorSupport,

这其实是java.beans的一个实现,里面有get和set方法用来做数据转换处理的操作,而这个value是作为一个数据的缓存,当然这里的set方法默认,通常我们需要重写这个方法达到自定义转换器,下面我们写一个demo。

首先创建一个继承PropertyEditorSupport的类,这里我们采用String类型转换Properties

package convert;

import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;

public class StringToPropertyEditor extends PropertyEditorSupport {

  public static void main(String[] args) {
    StringToPropertyEditor stringToUserPropertyEditor=
        new StringToPropertyEditor();

    String stringToProperty = "name = 大帅比";
    System.out.println(stringToProperty);
    stringToUserPropertyEditor.setAsText(stringToProperty);
    System.out.println(stringToUserPropertyEditor.getAsText());
  }

  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    // 创建目标转换类型
    Properties properties=new Properties();
    try {
      properties.load(new StringReader(text));
    } catch (IOException e) {
      e.printStackTrace();
    }
    // 将转换值传入PropertyEditorSupport的 value
    setValue(properties);

  }
}

通过结果对比可以看到我们的数据从String类型转换为了Properties,下面我们结合Spring实现自定义PropertyEditor

首先还是注册一个StringToPropertyEditor,然后再定义一个类实现PropertyEditorRegistrar ,这个类有个方法registerCustomEditors方法,然后我们可以通过参数PropertyEditorRegistry 实现注册,将我们自定义的CustomizedPropertyEditorRegistrar 交给Spring管理

@Component
public class CustomizedPropertyEditorRegistrar implements PropertyEditorRegistrar {

  @Override
  public void registerCustomEditors(PropertyEditorRegistry registry) {

    //  注册自定义转换器
    registry.registerCustomEditor(Properties.class,new StringToPropertyEditor());

  }
}

我们再写一个实体类


@Component
public class Person {

  //  需要被转换的目标类
  private Properties property;

  private Integer age;

  private String name;

  public Integer getAge() {
    return age;
  }

  public Properties getProperty() {
    return property;
  }

  public void setProperty(Properties property) {
    this.property = property;
  }

  public void setAge(Integer age) {
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

实体类写完后注意这里我们需要对我们的Person对象进行赋值,这里我们采用后置处理器的方式赋值


@Component
public class MyBeanPostProcessor implements BeanFactoryPostProcessor {

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    GenericBeanDefinition bd= (GenericBeanDefinition) beanFactory.getBeanDefinition("person");
    /*BeanDefinition customEditorConfigurer= (GenericBeanDefinition) beanFactory.getBeanDefinition("customEditorConfigurer");*/
    bd.getPropertyValues().addPropertyValue("property","name = 大帅比");
/*    customEditorConfigurer.getPropertyValues().addPropertyValue("propertyEditorRegistrars",new CustomizedPropertyEditorRegistrar());*/
  }
}

很简单就是通过后置处理器对我们person对象的property属性赋值"name = 大帅比"

好了准备工作完毕我们开始写测试类

public static void main(String[] args) {
      AnnotationConfigApplicationContext annotationConfigApplicationContext=
          new AnnotationConfigApplicationContext(AppConfig.class);

      Person person= (Person) annotationConfigApplicationContext.getBean("person");

      System.out.println(person.getProperty());

测试类很简单就是启动我们的容器然后获取person的Property属性,好了我们运行一下看看有没有结果

可以看到这里并没有被执行,说明我们自定义失效,那么我们如何解决这个问题呢?其实很简单我们直接通过后置处理器手动注册CustomEditorConfigurer,为什么注册这个类,因为我们的工作类其实就是通过CustomEditorConfigurer去循环执行我们自定义的PropertyEditor,因此如果我们没有手动创建它,我们其实无法注册PropertyEditor

 

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{

  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) throws IllegalAccessException, InstantiationException {
    BeanDefinitionBuilder beanDefinitionBuilder=BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
    GenericBeanDefinition bd= (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();

    bd.getPropertyValues().addPropertyValue("propertyEditorRegistrars",new CustomizedPropertyEditorRegistrar());

    registry.registerBeanDefinition("customEditorConfigurer",bd);
  }
}

好了,我们再次执行

可以看到我们达到了我们的目的,那么为什么我们需要手动注册呢?这里哦我们修改一下我们的后置处理器MyBeanPostProcessor

@Component
public class MyBeanPostProcessor implements BeanFactoryPostProcessor {

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    GenericBeanDefinition bd= (GenericBeanDefinition) beanFactory.getBeanDefinition("person");
    BeanDefinition customEditorConfigurer= (GenericBeanDefinition) beanFactory.getBeanDefinition("customEditorConfigurer");
    System.out.println(customEditorConfigurer);
    
    bd.getPropertyValues().addPropertyValue("property","name = 大帅比");
/*    customEditorConfigurer.getPropertyValues().addPropertyValue("propertyEditorRegistrars",new CustomizedPropertyEditorRegistrar());*/
  }
}

然后我们再关闭我们的MyImportBeanDefinitionRegistrar

再次执行

说明Spring并没有创建,而是在需要的时候创建,这里为什么说是在需要的时候才创建,因为在Bean实例的章节笔者提到了一个接口BeanWapper,为什么Spring不直接将对象处理而是要封装成BeanWapper的方式,其实就是源于数据转换,这个我们后面再说,好了我们对PropertyEditor注册进行了详细的描述,下面将介绍PropertyEditor的缺点以及Spring为什么推出新的接口方式。

PropertyEditor的缺陷

前面我们的大量的提到了PropertyEditor的作用基于注册方式,但我们或许已经发现PropertyEditor在某些场景上却不能得心应手,比如如果我们不再是String类型作为数据源,而是其他类型转换为字符类型这时PropertyEditor就无法满足,其次如果我们是多个类型转换PropertyEditor依旧不能满足。那么Spring在3.0就提出了新的转换器Converter

这里应该大家也能够猜到,Converter的能够安全开放数据源和目标类,也就是说我们不再一定需要固定的String转换为其他类型,那么为什么Spring在3.0提出的这套标准,个人猜测我们都知道在Spring2.x的版本里,我们都是采用xml的方式用来处理Bean,而xml的方式就会涉及到String类型转换为目标类型,而在Spring 3.0已经推出注解Bean,因此我们不在一定是字符的方式作为转换的数据源,这就变得十分灵活,而PropertyEditor就不能满足我们的需要,当然这只是笔者的猜测,但个人认为这不一定没有道理,好了废话了那么多我们开始对Converter进行简单的描述。

Converter

前面我们已经对Converter有了一定的了解,现在我们看看他的一些子实现。

可以看到这里有很多的Converter实现,而且这些实现并不是String类型作为数据源,这也是Spring新建Converter的目的之一,当然我们实现了各类各样的接口去完善转换器,这会导致一个问题,当我们去做转换处理时我们不能需要判断的次数是否太多,我们在看看下面这个接口

这个接口用来优化匹配次数,如果我们的类即Converter又实现了ConditionalConverter,那么Spring底层会有限执行ConditionalConverter的matches方法对转换器进行筛选,我们具体看看它是如何实现的,我们定位一个子类

可以看到它实现了ConditionalGenericConverter,我们点进去看看

这里可以看到它继承了GenericConverter, ConditionalConverter,ConditionalConverter我们都知道是用来匹配筛选类的,而GenericConverter是用来干嘛的呢?

这里其实也是一个转换器只是它用来可以用来处理集合方式的类型转换,这也是PropertyEditor不能实现的一点,我们暂且将它当做普通的converter,好了我们回到

可以看到我们两个子实现方法matches、convert,这里有个我们关注一个属性,而这两个方法都是寄托CollectionToStringConverter转换

我们点开这个属性看看,

它依旧实现了ConditionalGenericConverter,说明它才是处理数据转换的源头,这里简单解释下ConditionalGenericConverter设计的方式,假如我们的A类的一些属性需要转换,这个时候会去获取合适的转换器,步骤和PropertyEditor类似,但是他会先去调用ConditionalConverter的matches方法如果匹配成功那么直接返回true说明找到了符合数据源类型和数据目标类型的组,于是从GenericConverter的子实现去调用Set<ConvertiblePair> getConvertibleTypes();如果matches返回false,那就只能按照普通的方式查找。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值