青年时种下什么,老年时就收获什么。关注公众号【BAT的乌托邦】,有Spring技术栈、MyBatis、JVM、中间件等小而美的原创专栏供以免费学习。分享、成长,拒绝浅尝辄止。本文已被 https://www.yourbatman.cn 收录。

目录

  • ✍前言
    • 版本约定
  • ✍正文
    • PropertyEditor是什么?
      • 注意:PropertyEditorSupport线程不安全
    • Spring为何基于它扩展?
    • Spring内建扩展实现有哪些?
      • 标准实现示例
      • 特殊实现
    • “谁”在使用ProertyEditor
    • PropertyEditor自动发现机制
    • PropertyEditor存在的缺陷
  • ✍总结
    • 附:Spring主要版本发布时间和特性
      • ✔推荐阅读:
  • ♥关注A哥♥

✍前言

你好,我是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上你可以输入、编辑某个属性然后经过它转换成合适的类型。

此接口提供的方法挺多的,和本文类型转换有关的最多只有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的基础上只需要复写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
@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
@Test
public void test2() {// 虽然都行,但建议你规范书写:UTF-8PropertyEditor editor = new CharsetEditor();editor.setAsText("UtF-8");System.out.println(editor.getAsText()); // UTF-8editor.setAsText("utF8");System.out.println(editor.getAsText()); // UTF-8
}

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

  • CustomDateEditor
@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等等与资源相关的转换器,均依赖它而实现
@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喽,咱们拭目以待。


✔推荐阅读:
  • 1. 揭秘Spring类型转换 - 框架设计的基石
  • 蚂蚁金服上市了,我不想努力了
  • 如果程序员和产品经理都用凡尔赛文学对话…
  • 程序人生 | 春风得意马蹄疾,一日看尽长安花

♥关注A哥♥

Author A哥(YourBatman)
个人站点 www.yourbatman.cn
E-mail yourbatman@qq.com
微 信 fsx1056342982
活跃平台
公众号 BAT的乌托邦(ID:BAT-utopia)
知识星球 BAT的乌托邦
每日文章推荐 每日文章推荐

2. Spring早期类型转换,基于PropertyEditor实现相关推荐

  1. Spring 2.5 基于注解驱动的 Spring MVC

    基于注解的配置有越来越流行的趋势,Spring 2.5 顺应这种趋势,为 Spring MVC 提供了完全基于注解的配置.本文将介绍 Spring 2.5 新增的 Sping MVC 注解功能,讲述如 ...

  2. 使用 Spring 2.5 基于注解驱动的 Spring MVC--转

    概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Spring 2.5 又为 Spring MVC 引入了注解驱动功能.现在你无须让 Controller 继承任何接口,无需在 ...

  3. Spring整合JMS——基于ActiveMQ实现(一)

    Spring整合JMS--基于ActiveMQ实现(一) 1.1     JMS简介 JMS的全称是Java Message Service,即Java消息服务.它主要用于在生产者和消费者之间进行消息 ...

  4. html 变量类型强制转换,html、js前台数据传到后台,spring复杂类型转换

    html.js前台数据传到后台,spring复杂类型转换 如果我有两个变量,变量名不一样,处理的规则也不一样,但是他们都是Date.class 类型, 这可怎么破.比如: @InitBinder pu ...

  5. Spring Boot2.x-10 基于Spring Boot 2.1.2 + Mybatis 2.0.0实现多数据源,支持事务

    文章目录 概述 思路 步骤 Step1 多数据源配置文件applicaiton.yml Step2 初始化多个数据源 Step3 配置多个数据源 验证测试 支持事务 Step1 配置类中通过@Bean ...

  6. Spring Cache抽象-基于XML的配置声明(基于EhCache的配置)

    概述 完整示例 pomxml增加依赖 数据库表数据Oracle 实体类 服务层 ehcache的配置文件 Spring-EhCache配置文件 单元测试 日志输出 日志分析 示例源码 概述 首先请阅读 ...

  7. 实践出真知之Spring Cloud之基于Eureka、Ribbon、Feign的真实案例

    转载自  实践出真知之Spring Cloud之基于Eureka.Ribbon.Feign的真实案例 Eureka是Spring Cloud Eureka的简称,是Netflix提供的组件之一.通过E ...

  8. Spring Boot之基于Redis实现MyBatis查询缓存解决方案

    转载自 Spring Boot之基于Redis实现MyBatis查询缓存解决方案 1. 前言 MyBatis是Java中常用的数据层ORM框架,笔者目前在实际的开发中,也在使用MyBatis.本文主要 ...

  9. Spring Boot之基于Dubbo和Seata的分布式事务解决方案

    转载自 Spring Boot之基于Dubbo和Seata的分布式事务解决方案 1. 分布式事务初探 一般来说,目前市面上的数据库都支持本地事务,也就是在你的应用程序中,在一个数据库连接下的操作,可以 ...

最新文章

  1. openSUSE11.1 用Yast安装virtualbox 2.06
  2. 财报上的云计算战场: 巨头们垄断加剧
  3. 【ArchSummit北京2015】公有云平台发展与建设实战解析
  4. tensorflow 迁移学习_基于 TensorFlow.js 1.5 的迁移学习图像分类器
  5. When 多模态 meets 信息抽取
  6. oracle中的输入 amp,Oracle之SQL学习
  7. MacFetionV0.8.0测试版
  8. Bootstrap下拉菜单标题
  9. 编译x264出现错误:No working C compiler found.
  10. Springboot异常--Identify and stop the process that‘s listening on port 9090 or configure this applicat
  11. vue实现按钮倒计时功能
  12. vue中使用layui实现树形菜单增删改查功能
  13. H5--大概的,没事看看
  14. 模糊C均值聚类以及C实现
  15. 与MP3相关的技术总结
  16. 87金融汇:如何理性看待互联网理财收益波动
  17. 人工神经网络的训练步骤,人工神经网络建模步骤
  18. C#减少图片文件大小和尺寸(转)
  19. 关于img的两个问题
  20. 机器人课程教师面对的困境有哪些

热门文章

  1. 不能忍!花钱买网站VIP账号别人在用?
  2. ecshop 评价仿京东仿淘宝 中评率 好评率 差评率
  3. OSError: Unable to create file (unable to open file: name = ‘../working/best.hdf5 No such file or di
  4. 2021-05-26SEO关键词KPI考核指标有哪些
  5. mac mtu测试_从Mac OS X的命令行设置MTU大小
  6. 关于介绍最好用的windows10系统的文章
  7. IE浏览器如何获取本地ip地址
  8. API中endpoints是什么意思?
  9. 一款勒索病毒的详细分析
  10. (生物信息学)R语言绘图初-中-高级——3-10分文章必备——Venn图(韦恩图)(初级)