在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(4);
    private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap(4);
    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(8);
    private SecurityContextProvider securityContextProvider;
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap(256);
    private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap(256));
    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 = 2147483647;
    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 
}
}

}