共计 7550 个字符,预计需要花费 19 分钟才能阅读完成。
青年时种下什么,老年时就播种什么。关注公众号【BAT 的乌托邦 】,有 Spring 技术栈、MyBatis、JVM、中间件等小而美的 原创专栏 供以收费学习。分享、成长,回绝浅尝辄止。本文已被 https://www.yourbatman.cn 收录。
✍前言
你好,我是 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 个:
void setValue(Object value)
:设置属性值Object getValue()
:获取属性值String getAsText()
:输入。把属性值转换成 String 输入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 抉择这么干而没本人重整旗鼓的起因可能有这么几个:
- 本着不反复创造轮子的准则,有得用就间接用呗,况且是 100% 满足要求的
- 示好 Java EE 技术。毕竟那会 Spring 位置还并不稳,有大腿就先榜上
-
2003 年左右,Java GUI 程序还并未退出历史舞台,Spring 为了通用性就抉择基于它扩大喽
- 阐明:那会的通用性可能和当初通用性含意上是不一样的,须要稍作区别
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-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:
@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!
✍总结
本文次要介绍了三点内容:
- PropertyEditor 是什么?
- Spring 为何抉择基于 PropertyEditor?
- 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 |
yourbatman@qq.com | |
微 信 | fsx1056342982 |
沉闷平台 |
|
公众号 | BAT 的乌托邦(ID:BAT-utopia) |
常识星球 | BAT 的乌托邦 |
每日文章举荐 | 每日文章举荐 |