首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2. Spring早期类型转换,基于PropertyEditor实现

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

作者头像
YourBatman
发布于 2022-03-08 07:02:16
发布于 2022-03-08 07:02:16
90410
代码可运行
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦
运行总次数:0
代码可运行

目录

✍前言

你好,我是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的介绍也无出其右:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
A PropertyEditor class provides support for GUIs that want to allow users to edit a property value of a given type.

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

此接口提供的方法挺多的,和本文类型转换有关的最多只有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为此提供了一个成员属性来做:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
PropertyEditorSupport:

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

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

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

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

Spring为何基于它扩展?

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

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

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

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

Spring内建扩展实现有哪些?

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

PropertyEditor

功能

举例

ZoneIdEditor

转为java.time.ZoneId

Asia/Shanghai

URLEditor

转为URL,支持传统方式file:,http:,也支持Spring风格:classpath:,context上下文相对路径等等

http://www.baidu.com

StringTrimmerEditor

trim()字符串,也可删除指定字符char

任意字符串

StringArrayPropertyEditor

转为字符串数组

A,B,C

PropertiesEditor

转为Properties

name = YourBatman

PatternEditor

转为Pattern

(\D*)(\d+)(.*)

PathEditor

转为java.nio.file.Path。支持传统URL和Spring风格的url

classpath:xxx

ClassEditor

转为Class

全类名

CustomBooleanEditor

转为Boolean

见示例

CharsetEditor

转为Charset

见示例

CustomDateEditor

转为java.util.Date

见示例

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

标准实现示例

  • CustomBooleanEditor
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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,将在后面进行讲述对比

  • CharsetEditor
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test2() {
    // 虽然都行,但建议你规范书写:UTF-8
    PropertyEditor editor = new CharsetEditor();
    editor.setAsText("UtF-8");
    System.out.println(editor.getAsText()); // UTF-8
    editor.setAsText("utF8");
    System.out.println(editor.getAsText()); // UTF-8
}

关注点:utf-8中间的横杠可要可不要,但建议加上使用标准写法,另外字母也是不区分大小写的。

  • CustomDateEditor
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test3() {
    PropertyEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),true);
    editor.setAsText("2020-11-30 09:10:10");
    System.out.println(editor.getAsText()); // 2020-11-30 09:10:10

    // null输出空串
    editor.setAsText(null);
    System.out.println(editor.getAsText());

    // 报错
    editor.setAsText("2020-11-30");
    System.out.println(editor.getAsText());
}

关注点:这个时间/日期转换器很不好用,构造时就必须指定一个SimpleDateFormat格式化器。在实际应用中,Spring并没有使用到它,而是用后面会说到的替代方案。

特殊实现

把没有放在org.springframework.beans.propertyeditors包下的实现称作特殊实现(前者称为标准实现)。

  • MediaTypeEditor:位于org.springframework.http。依赖的核心API是MediaType.parseMediaType(text),可以把诸如text/html、application/json转为MediaType对象
    • 显然它属于spring-web包,使用在web环境下
  • FormatterPropertyEditorAdapter:位于org.springframework.format.support。将3.0新增的Formatter接口适配为一个PropertyEditor:setAsText这种转换操作委托给formatter.parse()去完成,反向委托给formatter.print()去完成。
    • 此适配器在DataBinder#addCustomFormatter()得到应用
  • PropertyValuesEditor:位于org.springframework.beans。将k-v字符串(Properties格式)转换为一个PropertyValues,从而方便放进Environment里
  • ResourceEditor:位于org.springframework.core.io。此转换器将String转换为Resource资源,特别实用。作为基础设施,广泛被用到Spring的很多地方
    • 像什么标准的FileEditor、InputSourceEditor、InputStreamEditor、URLEditor等等与资源相关的转换器,均依赖它而实现
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test4() {
    // 支持标准URL如file:C:/myfile.txt,也支持classpath:myfile.txt
    // 同时还支持占位符形式
    PropertyEditor editor = new ResourceEditor(new DefaultResourceLoader(), new StandardEnvironment(), true);

    // file:形式本处略
    // editor.setAsText("file:...");
    // System.out.println(editor.getAsText());

    // classpath形式(注意:若文件不存在不会报错,而是输出null)
    editor.setAsText("classpath:app.properties");
    System.out.println(editor.getAsText()); // 输出带盘符的全路径

    System.setProperty("myFile.name", "app.properties");
    editor.setAsText("classpath:${myFile.name}");
    System.out.println(editor.getAsText()); // 结果同上
}

关注点:Spring扩展出来的Resource不仅自持常规file:资源协议,还支持平时使用最多的classpath:协议,可谓非常好用。

  • ConvertingPropertyEditorAdapter:位于org.springframework.core.convert.support。将3.0新增的ConversionService转换服务适配为一个PropertyEditor,内部转换动作都委托给前者去完成。
    • AbstractPropertyBindingResult#findEditor()为属性寻找合适PropertyEditor的时候,若ConversionService能支持就包装为ConvertingPropertyEditorAdapter供以使用,这是适配器模式的典型应用场景。

“谁”在使用ProertyEditor

PropertyEditor自动发现机制

PropertyEditor存在的缺陷

考虑到阅读的舒适性,单篇文章不宜太长,因此涉及到PropertyEditor的这几个问题,放在下篇文章单独列出。这个几个问题会明显比本文更深入,欢迎保持持续关注,peace!

✍总结

本文主要介绍了三点内容:

  1. PropertyEditor是什么?
  2. Spring为何选择基于PropertyEditor?
  3. Spring内建的那些PropertyEditor都有哪些,各自什么作用?

PropertyEditor虽然已经很古老,不适合当下复杂环境。但不可否认它依旧有存在的价值,Spring内部也大量的仍在使用,因此不容忽视。下篇文章将深度探讨Spring内部是如何使用PropertyEditor的,赋予了它哪些机制,以及最终为何还是决定自己另起炉灶搞一套呢?欢迎对本系列保持持续关注~


附:Spring主要版本发布时间和特性

  • 2002-02,开始开发孵化此项目,项目名叫:interface21,它便就是Spring的前身
  • 2004-03,1.0版发布。进入迅速发展期
  • 2006-10,2.0版发布。支持可扩展的xml配置功能、支持Java5、支持动态语言、支持更多扩展点
  • 2007-11,2.5版发布。项目名从此改为Spring Source,支持Java 6,支持注解配置(部分)
  • 2009-12,3.0版发布。这是非常非常重要的一个版本,支持了模块驱动、支持SpEL、支持Java Bean配置、支持嵌入式数据库
  • 2011和2012,这两年发布了非常多的3.x系列小版本,带来了很多惊喜,同时也让Spring更加扎实
  • 2013-12,4.0版发布。这是有一次进步,提供了对Java 8的全面支持,支持Java EE 7、支持websocket、泛型依赖注入…
  • 2017-09,5.0版发布。最低JDK版本要求是Java 8,同时支持Servlet 3.1。当然最为重要的是引入了全新模块:WebFlux

截止到当前,Spring Framework的最新版本是5.3.x版本,此版本是5.x的最后一个主要功能分支,下个版本将是6.x喽,咱们拭目以待。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
very nice!
very nice!
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
2. Spring早期类型转换,基于PropertyEditor实现
Spring早在1.0(2004年发布,2003年孵化中)的时候,就有了类型转换功能模块。此模块存在的必要性不必多说,相信每个同学都可理解。最初,Spring做类型转换器是基于Java标准的java.beans.PropertyEditor这个API去扩展实现的,直到Spring 3.0后才得以出现更好替代方案(Spring 3.0发布于2009 年12月)。
YourBatman
2020/12/08
7280
2. Spring早期类型转换,基于PropertyEditor实现
1. 揭秘Spring类型转换 - 框架设计的基石
Spring Framework是一个现代化的框架,俨然已发展成为Java开发的基石。随着高度封装、高度智能化的Spring Boot的普及,发现团队内越来越少的人知道其深层次机制,哪怕只有一点点。这是让Spirng团队开心,但却是让使用的团队比较担忧的现象。
YourBatman
2020/12/01
1.5K0
1. 揭秘Spring类型转换 - 框架设计的基石
3. 搞定收工,PropertyEditor就到这
上篇文章介绍了PropertyEditor在类型转换里的作用,以及举例说明了Spring内置实现的PropertyEditor们,它们各司其职完成 String <-> 各种类型 的互转。
YourBatman
2022/03/08
5910
3. 搞定收工,PropertyEditor就到这
SpringMVC类型转换器、属性编辑器PropertiesEditor源码分析CustomDateEditor源码分析TypeConverterDelegate源码分析
对于MVC框架,参数绑定一直觉得是很神奇很方便的一个东西,在参数绑定的过程中利用了属性编辑器、类型转换器 参数绑定流程 参数绑定:把请求中的数据,转化成指定类型的对象,交给处理请求的方法 请求进入到D
用户1174983
2018/02/05
1.2K0
SpringMVC类型转换器、属性编辑器PropertiesEditor源码分析CustomDateEditor源码分析TypeConverterDelegate源码分析
SpringMVC注解 @initbinder 解决类型转换问题
使用 SpringMVC 时,常遇到表单中日期字符串和 JavaBean 的 Date 类型的转换,而 SpringMVC 默认不支持这个格式的转换,故需要手动配置,自定义数据的绑定才能解决这个问题。 在需要日期转换的 Controller 中使用 SpringMVC 的注解 @initbinder 和 Spring 自带的 WebDateBinder 类来操作。 WebDataBinder 是用来绑定请求参数到指定的属性编辑器.由于前端传到 controller 里的值是 String 类型的,当往 Model 里 Set这个值的时候,如果 set 的这个属性是个对象,Spring 就会去找到对应的 editor 进行转换,然后再 SET 进去。 代码如下:
微风-- 轻许--
2019/07/02
6570
SpringMVC注解@initbinder解决类型转换问题
在使用SpringMVC的时候,经常会遇到表单中的日期字符串和JavaBean的Date类型的转换,而SpringMVC默认不支持这个格式的转换,所以需要手动配置,自定义数据的绑定才能解决这个问题。 在需要日期转换的Controller中使用SpringMVC的注解@initbinder和Spring自带的WebDateBinder类来操作。 WebDataBinder是用来绑定请求参数到指定的属性编辑器.由于前台传到controller里的值是String类型的,当往Model里Set这个值的时候,如果set的这个属性是个对象,Spring就会去找到对应的editor进行转换,然后再SET进去。 代码如下:
wuweixiang
2018/08/14
3870
Spring读源码系列番外篇04----类型转换--上---老旧的PropertyEditor
Spring读源码系列番外篇—02—PropertyResolver的结构体系剖析—上
大忽悠爱学习
2022/05/10
7260
Spring读源码系列番外篇04----类型转换--上---老旧的PropertyEditor
3. 搞定收工,PropertyEditor就到这
上篇文章介绍了PropertyEditor在类型转换里的作用,以及举例说明了Spring内置实现的PropertyEditor们,它们各司其职完成 String <-> 各种类型 的互转。
YourBatman
2020/12/17
9150
3. 搞定收工,PropertyEditor就到这
Spring Boot:定制PropertyEditors
在Spring Boot: 定制HTTP消息转换器一文中我们学习了如何配置消息转换器用于HTTP请求和响应数据,实际上,在一次请求的完成过程中还发生了其他的转换,我们这次关注将参数转换成多种类型的对象,如:字符串转换成Date对象或字符串转换成Integer对象。
阿杜
2018/08/06
4050
【小家Spring】聊聊Spring中的数据转换:Converter、ConversionService、TypeConverter、PropertyEditor
前面聊了HttpMessageConverter,它的名称叫消息转换器,所以它面向的是消息体,和Http强相关,所以该接口所在的包为:org.springframework.http.converter
YourBatman
2019/09/03
6.5K0
【小家Spring】聊聊Spring中的数据转换:Converter、ConversionService、TypeConverter、PropertyEditor
1. 揭秘Spring类型转换 - 框架设计的基石
Spring Framework是一个现代化的框架,俨然已发展成为Java开发的基石。随着高度封装、高度智能化的Spring Boot的普及,发现团队内越来越少的人知道其深层次机制,哪怕只有一点点。这是让Spirng团队开心,但却是让使用的团队比较担忧的现象。
YourBatman
2022/03/08
9600
1. 揭秘Spring类型转换 - 框架设计的基石
spring源码篇(二)核心概念熟悉
spring中的几个核心概念,在看源码前先了解这些概念,后面再去看源码会更容易理解源码。
用针戳左手中指指头
2021/03/22
6070
[Java web]– spring3(2)「建议收藏」
===============================================================================================
全栈程序员站长
2022/10/04
2210
Spring复杂的BeanFactory继承体系该如何理解? ----上
Spring提供了两种容器类型:BeanFactory和ApplicationContext。
大忽悠爱学习
2022/05/10
2K0
Spring复杂的BeanFactory继承体系该如何理解? ----上
Spring5参考指南: BeanWrapper和PropertyEditor
org.springframework.beans 包里面有个很重要的类叫做BeanWrapper接口和他的实现BeanWrapperImpl,BeanWrapper提供了设置和获取属性值(单个或批量)、获取属性描述符和查询属性的功能,以确定它们是可读的还是可写的。
程序那些事
2020/07/08
7080
Spring官网阅读系列(十一):Spring中的BeanWrapper及类型转换
BeanWrapper的子类只有一个:BeanWrapperImpl,它继承了ConfigurablePropertyAccessor,这个接口的主要功能是进行属性访问,同时它又有三个父接口,接下来我们一一分析他们的功能。
秃顶的Java程序员
2020/03/29
1.4K0
Spring ApplicationContext 简介
ApplicationContext是对BeanFactory的扩展,实现BeanFactory的所有功能,并添加了事件传播,国际化,资源文件处理等。
WindWant
2020/09/11
5590
Spring数据绑定之 WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...---02
上一篇我们对DataBinder的源码进行了详细的分析,下面我们对DataBinder的实现子类来做一下具体分析:
大忽悠爱学习
2022/08/23
5140
Spring数据绑定之 WebDataBinder、ServletRequestDataBinder、WebBindingInitializer...---02
Spring 核心概念
在前一篇我们了解了 Spring IOC, Spring AOP 的强大,以及对我们编程范式,编程基础的影响。接下来我们一起来聊一下 Spring 基础概念。对于基础概念而言基本上都是属于那种字典类型的会有一定的枯燥程度,大佬文末见。
没有故事的陈师傅
2023/05/01
2920
Spring 核心概念
从原理层面掌握@InitBinder的使用【享学Spring MVC】
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
YourBatman
2019/09/18
3.5K0
推荐阅读
相关推荐
2. Spring早期类型转换,基于PropertyEditor实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档