spring 容器中TypeConverter对象的使用

TypeConverter在同期容器中的创建及初始化

spring的容器中有很多地方会用的类型转换,spring使用TypeConverter做类型转换,现在我们来分析TypeConverter是如何在spring的容器中使
在AbstractBeanFactory对象下面定义了属性typeConverter,代码如下:

    /** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
    private TypeConverter typeConverter;

会覆盖默认PropertyEditor机制,该对象可以设置一个自定义的对象,如果没有设置,会使用SimpleTypeConverter作为默认实现类,
同时会将beanFatory中定义的两个属性

    /** Custom PropertyEditorRegistrars to apply to the beans of this factory */
    private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =
            new LinkedHashSet<PropertyEditorRegistrar>(4);
    /** Custom PropertyEditors to apply to the beans of this factory */
    private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
            new HashMap<Class<?>, Class<? extends PropertyEditor>>(4);

设置到TypeConverter的属性

    private Map<Class<?>, PropertyEditor> customEditors;

中,会将beanFatory定义的属性

    /** Spring ConversionService to use instead of PropertyEditors */
    private ConversionService conversionService;

设置到TypeConverter的属性

    private ConversionService conversionService;

中,获取该对象的相关方法如下:

方法1:

    /**
     * 获取BeanFactory中的属性typeConverter。如果属性typeConverter为空,
     * 那么每次都会创建一个SimpleTypeConverter对象,因为内部使用的是PropertyEditor作为类型转换,
     * PropertyEditor通常不是线程安全的,因为内部是有状态的。如果默认的PropertyEditor机制是激活的,
     * 返回的的TypeConverter对象中能够感知到已经注册的custom editors。
     * Obtain a type converter as used by this BeanFactory. This may be a fresh
     * instance for each call, since TypeConverters are usually <i>not</i> thread-safe.
     * <p>If the default PropertyEditor mechanism is active, the returned
     * TypeConverter will be aware of all custom editors that have been registered.
     * @since 2.5
     */
    @Override
    public TypeConverter getTypeConverter() {
        TypeConverter customConverter = getCustomTypeConverter();
        if (customConverter != null) {
            return customConverter;
        }
        else {
            // Build default TypeConverter, registering custom editors.
            SimpleTypeConverter typeConverter = new SimpleTypeConverter();
            typeConverter.setConversionService(getConversionService());
            registerCustomEditors(typeConverter);
            return typeConverter;
        }
    }

方法2:

     /**
     * 返回自定义的TypeConverter
     * Return the custom TypeConverter to use, if any.
     * @return the custom TypeConverter, or {@code null} if none specified
     */
    protected TypeConverter getCustomTypeConverter() {
        return this.typeConverter;
    }

方法3:

    /**
     * 初始化TypeConvert对象,向其注册customEditors,customEditors在BeanFactory中可以被注册进来的。
     * customEditors在BeanWrappers中会使用到来转换bean的属性;也会在创建bean的时候转换构造函数的参数或者工厂方法的参数。
     * 官方解析:
     * Initialize the given PropertyEditorRegistry with the custom editors
     * that have been registered with this BeanFactory.
     * <p>To be called for BeanWrappers that will create and populate bean
     * instances, and for SimpleTypeConverter used for constructor argument
     * and factory method type conversion.
     * @param registry the PropertyEditorRegistry to initialize
     */
    protected void registerCustomEditors(PropertyEditorRegistry registry) {
        PropertyEditorRegistrySupport registrySupport =
                (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
        if (registrySupport != null) {
            registrySupport.useConfigValueEditors();
        }
        if (!this.propertyEditorRegistrars.isEmpty()) {
            //将属性beanFactory的属性propertyEditorRegistrars注册到TypeConvert的属性CustomEditors中
            for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
                try {
                    registrar.registerCustomEditors(registry);
                }
                catch (BeanCreationException ex) {
                    //...
                }
            }
        }
        if (!this.customEditors.isEmpty()) {
            //将属性beanFactory的属性customEditors注册到TypeConvert的属性CustomEditors中
            for (Map.Entry<Class<?>, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) {
                Class<?> requiredType = entry.getKey();
                Class<? extends PropertyEditor> editorClass = entry.getValue();
                registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass));
            }
        }
    }

spring容器中配置customEditors,propertyEditorRegistrars,conversionService对象。

下面看一下在beanFactory中是如何设置customEditors,propertyEditorRegistrars,conversionService对象的。

1.设置conversionService对象。

只要设置一个id=conversionService的bean就可以了,spring会自动注册到beanFactory的conversionService中来,源码分析如下:

我们知道spring的高级容器,如ClassPathXmlApplicationContext,会在刚开始就刷新容器,调用refresh方法,初始化所有的bean,
refresh方法在AbstractApplicationContext类中定义,代码如下

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

其中会调用finishBeanFactoryInitialization方法,代码如下:

    /**
     * Finish the initialization of this context's bean factory,
     * initializing all remaining singleton beans.
     */
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // Initialize conversion service for this context.
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }
        //···
    }

这段代码也是醉了,直接判断beanFactory中时候有名字为conversionService的bean,有的话就获取出来设置到conversionService属性中。

2.设置customEditors,propertyEditorRegistrars属性

我们知道如果要设置beanFactoy中定义的属性有几种方法,第一种就是上面提到的spring硬编码写死是哪个bean,还有一种就是实现BeanFactoryPostProcessor接口,
在上面的方法refresh中有句代码


    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);

该方法的具体内容:

    /**
     * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
     * respecting explicit order if given.
     * <p>Must be called before singleton instantiation.
     */
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    }

spring的高级中在创建bean之前会提前调用所有实现了BeanFactoryPostProcessor接口的bean.

spring中实现了一个bean用于向beanFactory中注册这个属性:org.springframework.beans.factory.config.CustomEditorConfigurer,参考配置如下

<!-- 自定义的属性编辑器 -->  
 <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
   <property name="propertyEditorRegistrars">
     <list>
       <bean class="mypackage.MyCustomDateEditorRegistrar"/>
       <bean class="mypackage.MyObjectEditorRegistrar"/>
     </list>
   </property>
 </bean>

 <!--<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
   <property name="customEditors">
     <map>
       <entry key="java.util.Date" value="mypackage.MyCustomDateEditor"/>
       <entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/>
     </map>
   </property>
 </bean>
 -->

在AbstractApplicationContext中有个方法prepareBeanFactory,也帮我们默认注册了一些资源相关的ropertyEditor对象,相关代码如下

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrResourceEditorRegistrar(this, getEnvironment()));

typeConverter对象解析

在spring中一开始是使用PropertyEditor对象来进行类型转换的,PropertyEditor对象有一些问题,只能转换字符串到对象,而且不是线程安全的,所以spring中重新新定义了
一个对象Converter由于类型转换,可以进行任意类型的转换,对外使用ConversionService,而TypeConverter对象正好是综合了这两个对象,
先尝试是用PropertyEditor转换器转换,如果没找到对应的转换器,会用ConversionService来进行对象转换。
TypeConverter接口描述如下:

/**
 * Interface that defines type conversion methods. Typically (but not necessarily)
 * implemented in conjunction with the {@link PropertyEditorRegistry} interface.
 *
 * <p><b>Note:</b> Since TypeConverter implementations are typically based on
 * {@link java.beans.PropertyEditor PropertyEditors} which aren't thread-safe,
 * TypeConverters themselves are <em>not</em> to be considered as thread-safe either.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see SimpleTypeConverter
 * @see BeanWrapperImpl
 */

由此可见,TypeConverter并不是线程安全的,虽然不是线程安全的,但是并不代表就不能使用,我们只要在使用的时候都重新创建一下就可以了,
正如上文的getTypeConverter方法一样。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值