在spring中, 提供了至少三种的 类型转换方式:   ConversionServiceFactoryBean, FormattingConversionServiceFactoryBean, CustomEditorConfigurer。

方式一:ConversionServiceFactoryBean

ConversionServiceFactoryBean 的用法是:

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters" >
<list>
<bean class="com.lk.StringToDateConverter">
<constructor-arg type="java.lang.String" value="MM-dd-yyyy"/>
</bean>
</list>
</property>
</bean>
public class StringToDateConverter implements Converter<String, Date> {
private Logger logger = Logger.getLogger(StringToDateConverter.class.getName());
private String datePattern;
public StringToDateConverter(String datePattern){
this.datePattern = datePattern; System.out.println("instantiating...converter with pattern : " + datePattern);
} public Date convert(String source) {
System.out.println("StringToDateConverter.convert");
try {
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
sdf.setLenient(false);
return sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
logger.info("date parse exception.");
}
return null;
}
}

方式二:FormattingConversionServiceFactoryBean

FormattingConversionServiceFactoryBean 跟ConversionServiceFactoryBean差不多, 也是需要bean 的名字必须是 conversionService

    <bean id="dateFormatter" class="com.lk.DateFormatter" >
<constructor-arg index="0" value="yyyy-MM-dd"></constructor-arg>
</bean> <bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<!-- 这里是我们自己定义的类型转换器 -->
<!-- 注意,这里首字母要小写,因为springmvc帮我们创建bean的时候,是以类名首字母小写命名 -->
<ref bean="dateFormatter"/>
</set>
</property>
</bean>

上面,bean 的名字必须是 conversionService , spring会去获取这个名字的bean ,找到了就注册为转换器。 其converters 属性中, 我们可以添加一些自定义的类型转换器。

至于为什么?

public class FormattingConversionServiceFactoryBean implements FactoryBean<FormattingConversionService>, EmbeddedValueResolverAware, InitializingBean {
private Set<?> converters;// 通过setter 设置
private Set<?> formatters;// 通过setter 设置
private Set<FormatterRegistrar> formatterRegistrars;// 可空,不为空的话, 注册 conversionService
private boolean registerDefaultFormatters = true;
private StringValueResolver embeddedValueResolver;
private FormattingConversionService conversionService; ... public void afterPropertiesSet() {
this.conversionService = new DefaultFormattingConversionService(this.embeddedValueResolver, this.registerDefaultFormatters);
ConversionServiceFactory.registerConverters(this.converters, this.conversionService); // 同时注册converter,和 conversionService
this.registerFormatters();// 注册 formatter
} private void registerFormatters() {
Iterator var1;
if(this.formatters != null) {
var1 = this.formatters.iterator(); while(var1.hasNext()) {
Object registrar = var1.next();
if(registrar instanceof Formatter) {
this.conversionService.addFormatter((Formatter)registrar); // 注册 formater其实就是把 formatter 添加到 conversionService中
} else {
if(!(registrar instanceof AnnotationFormatterFactory)) {
throw new IllegalArgumentException("Custom formatters must be implementations of Formatter or AnnotationFormatterFactory");
} this.conversionService.addFormatterForFieldAnnotation((AnnotationFormatterFactory)registrar);
}
}
} if(this.formatterRegistrars != null) {
var1 = this.formatterRegistrars.iterator(); while(var1.hasNext()) {
FormatterRegistrar registrar1 = (FormatterRegistrar)var1.next();
registrar1.registerFormatters(this.conversionService);
}
} } ...

位于AbstractApplicationContext:

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
if(beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
}
...

可见, bean 为 conversionService 且是一个  ConversionService 类型, 或其子类,就会生效。

上面的beanFactory 其实是AbstractBeanFactory ,它拥有很多有用的属性, 用于spring IoC

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
private BeanFactory parentBeanFactory;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private ClassLoader tempClassLoader;
private boolean cacheBeanMetadata = true;
private BeanExpressionResolver beanExpressionResolver;
private ConversionService conversionService;
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet();
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap();
private TypeConverter typeConverter;
private final List<StringValueResolver> embeddedValueResolvers = new LinkedList();
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList();
private boolean hasInstantiationAwareBeanPostProcessors;
private boolean hasDestructionAwareBeanPostProcessors;
private final Map<String, Scope> scopes = new LinkedHashMap();
private SecurityContextProvider securityContextProvider;
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap();
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap());
private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal("Prototype beans currently in creation");
...

方式三:CustomEditorConfigurer

CustomEditorConfigurer bean 的id 是可选的, 或者任意值都是ok 的。 但是他的配置稍微有些复杂, 它需要指定 customEditors 每一个 自定义转换器的entry的 类型。 比如, 如果我们需要把 String 转换为 java.util.Date, 那么需要指定 java.util.Date 为entry ,Spring 再尝试做转换的时候,会去 找到这个 entry 的转换器 然后转换它。 它的value 是 FQN, 这样的话,就不能配置转换器的 属性了,那么只能在转换器内部设置java 编码的 属性了。

    <bean id="anyIdOrName"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<value>com.lk.UtilDatePropertyEditor</value>
</entry>
</map>
</property>
</bean>

为什么不需要id 呢?因为:

public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered { 它实现了 BeanFactoryPostProcessor
protected final Log logger = LogFactory.getLog(this.getClass());
private int order = ;
private PropertyEditorRegistrar[] propertyEditorRegistrars;
private Map<Class<?>, Class<? extends PropertyEditor>> customEditors; // 专门用来注册 客户化自定义的 editors
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 这里有一个 beanFactory参数
if(this.propertyEditorRegistrars != null) {
PropertyEditorRegistrar[] var2 = this.propertyEditorRegistrars;
int entry = var2.length; for(int requiredType = 0; requiredType < entry; ++requiredType) {
PropertyEditorRegistrar propertyEditorClass = var2[requiredType];
beanFactory.addPropertyEditorRegistrar(propertyEditorClass);
}
} if(this.customEditors != null) {
Iterator var6 = this.customEditors.entrySet().iterator(); while(var6.hasNext()) {
Entry var7 = (Entry)var6.next();
Class var8 = (Class)var7.getKey();
Class var9 = (Class)var7.getValue();
beanFactory.registerCustomEditor(var8, var9); // 实际添加到了 AbstractBeanFactory 
}
} }

spring 之 类型转换的更多相关文章

  1. Spring ConversionService 类型转换(一)Converter

    Spring ConversionService 类型转换(一)Converter Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.h ...

  2. Spring ConversionService 类型转换(二) ConversionService

    Spring ConversionService 类型转换(二) ConversionService Spring 系列目录(https://www.cnblogs.com/binarylei/p/1 ...

  3. spring自动类型转换========Converter和PropertyEditor

    Spring有两种自动类型转换器,一种是Converter,一种是propertyEditor. 两者的区别:Converter是类型转换成类型,Editor:从string类型转换为其他类型. 从某 ...

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

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

  5. Spring MVC类型转换

    类型转换器引入 为什么页面上输入"12",可以赋值给Handler方法对应的参数?这是因为框架内部帮我们做了类型转换的工作.将String转换成int 但默认类型转换器并不是可以将 ...

  6. spring 之 类型转换 2

    spring内置的转换器 在spring xml 文件中,配置属性的时候, 不管实际是 list 还是map ,还是Date, 或者原生的java 类型, 我们只能配置xml 给它们. 那么 spri ...

  7. Spring MVC 类型转换

    SpringMVC类型转换: 1 日期类型转换: private Date birthday; <label for="">生日:<input type=&quo ...

  8. Spring类型转换(Converter)

    Spring的类型转换 以前在面试中就有被问到关于spring数据绑定方面的问题,当时对它一直只是朦朦胧胧的概念,最近稍微闲下来有时间看了一下其中数据转换相关的内容,把相应的内容做个记录. 下面先说明 ...

  9. Spring官网阅读(十四)Spring中的BeanWrapper及类型转换

    文章目录 接口定义 继承关系 接口功能 1.PropertyEditorRegistry(属性编辑器注册器) 接口定义 PropertyEditor 概念 Spring中对PropertyEditor ...

随机推荐

  1. nopi 简洁笔记

    导出excel /// <summary> /// 增加二维码 /// </summary> /// <param name="dt">< ...

  2. 从零开始学Shell(二)

    $1,$2....${10},${11},[root@localhost cee]# cat p.sh #!/bin/bash#file_name:p.shecho $1 $2[root@localh ...

  3. 发布-订阅消息系统Kafka简介

    转载请注明出处:http://www.cnblogs.com/BYRans/ Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写.Kafka是一种高吞吐量的分布式 ...

  4. mongodb初步使用体验

    前言 Mongodb是一个非常有名的缓存数据库,和它名气相当的还有redis和hbase.笔者之前使用过redis,memcache和elasticsearch,借着工作机会,正好可以好好学习一下mo ...

  5. python基础--字符串

    字符串 1.形式 单引号括起来的字符串:'hello' 双引号括起来的字符串:"Hello" 三引号括起来的字符串:'''hello'''(三单引号),""&q ...

  6. 清楚理解const_cast类型转换

    1.任何使用原常量的地方, 已经直接编码到代码中去了.故后续转换类型并不能改变原定义 2.const_cast转换, 是使用了新指针或者引用,指向了原定义的内存,故而可以修改该内存. 使用也得用新指针 ...

  7. PHP之缓存雪崩,及解决方法(转)

    一.什么是缓存雪崩缓存雪崩就是指缓存由于某些原因(比如 宕机.cache服务挂了或者不响应)整体crash掉了,导致大量请求到达后端数据库,从而导致数据库崩溃,整个系统崩溃,发生灾难. 下面的就是一个 ...

  8. 【leetcode】453. Minimum Moves to Equal Array Elements

    problem 453. Minimum Moves to Equal Array Elements 相当于把不等于最小值的数字都减到最小值所需要次数的累加和. solution1: class So ...

  9. 关于delete和delete[]的区别

    在C++动态内存分配中我们常用到new和delete两种操作,new用来申请内存,delete用来释放内存.那么问题来了,我们应该用delete来释放内存还是用delete[]来释放内存呢? 为了得到 ...

  10. web.html

    在“Web页”节点下,展开WEB-INF节点,然后双击web.xml文件进行查看. web.xml文件包含Facelets应用程序所需的几个元素.使用NetBeans IDE创建应用程序时,将自动创建 ...