Spring官方文档有专门一个章节阐述了BeanWrapper、DataBinder、ConversionService、Formatter。
同时也有相关章节阐述了Spring MVC中对其的运用:
不过很遗憾,官方文档对于如何在Standalone app和Spring MVC中应用这些东西讲的并不是很明白,本文旨在对BeanWrapper、DataBinder、ConversionService、Formatter做一个简单的概念解释,有助于开发人员利用这些工具。
基础概念
以下先讲解释一下这四个东西分别是干嘛的。
BeanWrapper
BeanWrapper是一个方便开发人员使用字符串来对Java Bean的属性执行get、set操作的工具类。比如:
Foo foo = new Foo();
BeanWrapperImpl fooWrapper = new BeanWrapperImpl(foo);
fooWrapper.setPropertyValue("intProperty", "1");
Object intProperty = fooWrapper.getPropertyValue("intProperty");
它为那些UI类app提供了极大的便利,因为这类app大部分情况下都是以字符串和用户交互的,这个很好理解吧,用户看到的数据都是文字,而不是一堆二进制。
BeanWrapper内部使用了两种机制:
PropertyEditor。PropertyEditor隶属于Java Bean规范。PropertyEditor只提供了String <-> Object的转换。
ConversionService。Spring自3.0之后提供的替代PropertyEditor的机制,后面会详细说。
按照Spring官方文档的说法,当容器内没有注册ConversionService的时候,会退回使用PropertyEditor机制。
ConversionService
ConversionService及其相关一套类型转换机制是一套通用的类型转换SPI,相比PropertyEditor只提供String<->Object的转换,ConversionService能够提供任意Object<->Object的转换。
所以我们可以猜测,Spring为何要使用ConversionService替代PropertyEditor有三个原因:
ConversionService功能更强大,支持的类型转换范围更广。
ConverterFactory支持一整个class hierarchy的转换(也就是多态),PropertyEditor则不行。
Java Bean这个规范最初是和Java GUI(Swing)一起诞生的,PropertyEditor接口里有大量和GUI相关的方法,显然已经过时了。顺便提一句,Java Bean和POJO不是一个概念,Java Bean不仅有setter、getter,还有一系列和Java GUI配套的东西。
Formatter
Formatter SPI是另外一套和PropertyEditor类似的,String<->Object的转换机制,但是有两个优点:
接口更干净,没有关于GUI的部分,只有
print
和parse
两个方法。基于注解,支持同一类型的属性根据不同的格式来做String<->Object的转换。比如日期类型,一个字段的格式是yyyy-MM-dd,另一个格式是yyyyMMdd,如果利用PropertyEditor是比较麻烦,但是在这里就可以利用
@DateTimeFormat
来达到这个效果。
Spring提供了DefaultFormattingConversionService来支持Formatter SPI,也就是说如果要使用Formatter SPI,依然可以利用ConversionService接口。
注意:Formatter SPI必须基于注解才可以使用,这点和ConversionService基于类型不同。
DataBinder
DataBinder主要提供了两个功能:
利用BeanWrapper,给对象的属性设值
在设值的同时做Validation
因为Validation不在本文探讨范围只能因此不做详述了。
关系
本小节讲一下BeanWrapper、DataBinder、ConversionService、Formatter之间的关系,以及Spring内部对它们的使用。
四者关系图
注意上图中ConversionService有两种实现:
DefaultConversionService,不支持Formatter SPI
DefaultFormattingConversionService,支持Formatter SPI
也就是说,如果要支持Formatter SPI,只需要让BeanWrapper切换使用不同的ConversionService即可。
Core Context的使用
Spring Core Context其实也使用ConversionService,但是是非强制的。
Spring在读取xml配置文件的时候,因为xml文件实际上是一个文本文件,所有值的设置都是String,这个时候如果给bean的复杂类型属性设置值,它会用到PropertyEditor或ConversionService。
比如下面例子中的color
属性是Color
类型,这时就会利用到PropertyEditor和ConversionService:
<bean id="someBean" class="a.b.c.SomeBean">
<property name="color" value="red"/>
</bean>
让Spring Core Context使用conversionService的方式很简单,配置一个名字叫做conversionService
的Bean即可。详情见9.5.5 Configuring a ConversionService。
需要注意的是,因为这个Bean是在非常早的时候就被使用的(AbstractApplicationContext#L834),因此它最好不要依赖过多的其他的Bean,避免造成启动失败。
MVC的使用
Spring MVC对于conversionService的使用比较特殊,它自己会注册一个名字叫做mvcConversionService
类型为DefaultFormattingConversionService
的Bean(代码在WebMvcConfigurationSupport#mvcConversionService)。因此会存在以下陷阱:
如果Core Context中也定义了一个
ConversionService
,那么在MVC环境下,会有两个ConversionService
的Bean。针对Core Context的
ConversionService
做的Customize如FormatterRegistrar、ConverterRegistry
、FormatterRegistry
、ConversionServiceFactoryBean
、FormattingConversionServiceFactoryBean
是不会应用到MVC的那个ConversionService
上。 对于mvcConversionService的配置途径见这里。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。