2. Spring早期类型转换,基于PropertyEditor实现(上)

简介: 2. Spring早期类型转换,基于PropertyEditor实现(上)

✍前言


你好,我是YourBatman。


Spring早在1.0(2004年发布,2003年孵化中)的时候,就有了类型转换功能模块。此模块存在的必要性不必多说,相信每个同学都可理解。最初,Spring做类型转换器是基于Java标准的java.beans.PropertyEditor这个API去扩展实现的,直到Spring 3.0后才得以出现更好替代方案(Spring 3.0发布于2009 年12月)。


提示:文章末尾附有Spring主要版本的发布时间和以及主要特性,感兴趣者可文末查看


虽说Spring自3.0就提出了更为灵活、优秀的类型转换接口/服务,但是早期基于PropertyEditor实现的转换器并未废弃且还在发挥余热中,因此本文就针对其早期类型转换实现做出专文讲解。


版本约定


  • Spring Framework:5.3.1
  • Spring Boot:2.4.0


说明:版本均于2020-11发布,且版本号均不带有.RELEASE后缀,这和之前是不一样的。具体原因请参考:Spring改变版本号命名规则:此举对非英语国家很友好


✍正文


若你用当下的眼光去看Spring基于PropertyEditor的类型转换实现,会发现这么搞是存在一些设计缺陷的。当然并不能这么去看,毕竟现在都2020年了,那会才哪跟哪呢。既然Spring里的PropertyEditor现如今依然健在,那咱就会会它呗。


PropertyEditor是什么?


PropertyEditor位于java.beans包中,要知道这个包里面的类都是设计为Java GUI程序(AWT)服务的,所以你看官方javadoc对PropertyEditor的介绍也无出其右:


A PropertyEditor class provides support for GUIs that want to allow users to edit a property value of a given type.


为GUI程序提供支持,允许你对给定的value进行编辑,作用类似于一个转换器:GUI上你可以输入、编辑某个属性然后经过它转换成合适的类型。

image.png


此接口提供的方法挺多的,和本文类型转换有关的最多只有4个:


  1. void setValue(Object value):设置属性值
  2. Object getValue():获取属性值
  3. String getAsText():输出。把属性值转换成String输出
  4. void setAsText(String text):输入。将String转换为属性值类型输入


JDK对PropertyEditor接口提供了一个默认实现java.beans.PropertyEditorSupport,因此我们若需扩展此接口,仅需继承此类,根据需要复写getAsText/setAsText这两个方法即可,Spring无一例外都是这么做的。


PropertyEditor作为一个JDK原生接口,内置了一些基本实现来服务于GUI程序,如:


  • BooleanEditor:将true/false字符串转换为Boolean类型
  • IntegerEditor:将字符串转换为Integer类型
  • 同类别的还有LongEditor、FloatEditor…


JDK内置的实现比较少(如上),功能简陋,但对于服务GUI程序来说已经够用,毕竟界面输入的只可能是字符串,并且还均是基础类型。但这对于复杂的Spring环境、以及富文本的web环境来说就不够用了,所以Spring在此基础上有所扩展,因此才有了本文来讨论。


注意:PropertyEditorSupport线程不安全


PropertyEditor实现的是双向类型转换:String和Object互转。调用setValue()方法后,需要先“缓存”起来后续才能够使用(输出)。PropertyEditorSupport为此提供了一个成员属性来做:

PropertyEditorSupport:
    // 调用setValue()方法对此属性赋值   getValue()方法取值
  private Object value;


这么一来PropertyEditorSupport就是有状态的了,因此是线程不安全的。在使用过程中需要特别注意,避免出现并发风险。


说明:Support类里还看到属性监听器PropertyChangeListener,因它属于GUI程序使用的组件,与我们无关,所以后续丝毫不会提及哦


Spring内置的所有扩展均是基于PropertyEditorSupport来实现的,因此也都是线程不安全的哦~


Spring为何基于它扩展?


官方的javadoc都说得很清楚:PropertyEditor设计是为GUI程序服务的,那么Spring为何看上它了呢?


试想一下:那会的Spring只能支持xml方式配置,而XML属于文本类型配置,因此在给某个属性设定值的时候,书写上去的**100%**是个字符串,但是此属性对应的类型却不一定是字符串,可能是任意类型。你思考下,这种场景是不是跟GUI程序(AWT)一毛一样:输入字符串,对应任意类型。


为了实现这种需求,在PropertyEditorSupport的基础上只需要复写setAsText和getAsText这两个方法就行,然后Spring就这么干了。我个人yy一下,当初Spring选择这么干而没自己另起炉灶的原因可能有这么几个:


  1. 本着不重复发明轮子的原则,有得用就直接用呗,况且是100%满足要求的
  2. 示好Java EE技术。毕竟那会Spring地位还并不稳,有大腿就先榜上
  3. 2003年左右,Java GUI程序还并未退出历史舞台,Spring为了通用性就选择基于它扩展喽

1.说明:那会的通用性可能和现在通用性含义上是不一样的,需要稍作区别


Spring内建扩展实现有哪些?


Spring为了扩展自身功能,提高配置灵活性,扩展出了非常非常多的PropertyEditor实现,共计40余个,部分截图如下:

image.png


image.png


Spring把实现基本(大多数)都放在org.springframework.beans.propertyeditors包下,接下来我挑选几个代表性API举例说明。


标准实现示例


  • CustomBooleanEditor


@Test
public void test1() {
    PropertyEditor editor = new CustomBooleanEditor(true);
    // 这些都是true,不区分大小写
    editor.setAsText("trUe");
    System.out.println(editor.getAsText());
    editor.setAsText("on");
    System.out.println(editor.getAsText());
    editor.setAsText("yes");
    System.out.println(editor.getAsText());
    editor.setAsText("1");
    System.out.println(editor.getAsText());
    // 这些都是false(注意:null并不会输出为false,而是输出空串)
    editor.setAsText(null);
    System.out.println(editor.getAsText());
    editor.setAsText("fAlse");
    System.out.println(editor.getAsText());
    editor.setAsText("off");
    System.out.println(editor.getAsText());
    editor.setAsText("no");
    System.out.println(editor.getAsText());
    editor.setAsText("0");
    System.out.println(editor.getAsText());
    // 报错
    editor.setAsText("2");
    System.out.println(editor.getAsText());
}

关注点:对于Spring来说,传入的true、on、yes、1等都会被“翻译”成true(字母不区分大小写),大大提高兼容性。


现在知道为啥你用Postman传个1,用Bool值也能正常封装进去了吧,就是它的功劳。此效果等同于转换器StringToBooleanConverter,将在后面进行讲述对比

相关文章
|
前端开发 Java Spring
Spring Boot 实现图片上传并回显
Spring Boot 实现图片上传并回显
|
NoSQL Java Redis
Spring boot整合Redis实现发布订阅(超详细)
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收信息。微信,微博,关注系统 Redis客户端可以订阅任意数量的频道
4787 0
Spring boot整合Redis实现发布订阅(超详细)
|
前端开发 Java Spring
《Spring MVC》 第六章 MVC类型转换器、格式化器
《Spring MVC》 第六章 MVC类型转换器、格式化器
190 0
|
JavaScript 前端开发 Java
Spring Boot+Vue实现汽车租赁系统(毕设)
一、前言 汽车租赁系统,很常见的一个系统,但是网上还是以前的老框架实现的,于是我打算从设计到开发都用现在比较流行的新框架。想学习或者做毕设的可以私信联系哦!!
437 19
Spring Boot+Vue实现汽车租赁系统(毕设)
|
XML JSON 前端开发
软件测试|Spring Boot 的 RESTful API 设计与实现
软件测试|Spring Boot 的 RESTful API 设计与实现
软件测试|Spring Boot 的 RESTful API 设计与实现
|
前端开发 Java 数据格式
Spring Boot实现文件上传
Spring Boot实现文件上传
607 0
|
Java Spring
Spring Boot+Netty实现远程过程调用(RPC)
Spring Boot+Netty实现远程过程调用(RPC)
|
存储 Java Apache
Spring Boot整合OpenOffice实现Word、Excel、PPT在线预览
Spring Boot整合OpenOffice实现Word、Excel、PPT在线预览
|
消息中间件 Java Spring
一文看懂Spring Boot整合Rabbit MQ实现多种模式的生产和消费
一文看懂Spring Boot整合Rabbit MQ实现多种模式的生产和消费
|
负载均衡 Java Nacos
手把手教你Spring Cloud Alibaba系列教程:Nacos实现服务注册与发现
手把手教你Spring Cloud Alibaba系列教程:Nacos实现服务注册与发现
339 0
手把手教你Spring Cloud Alibaba系列教程:Nacos实现服务注册与发现