spring 容器中TypeConverter对象的使用

      • TypeConverter在同期容器中的创建及初始化
      • spring容器中配置customEditorspropertyEditorRegistrarsconversionService对象
          • 设置conversionService对象
          • 设置customEditorspropertyEditorRegistrars属性
      • 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 propertyEditorRegistrars =
            new LinkedHashSet(4);
    /** Custom PropertyEditors to apply to the beans of this factory */
    private final Map, Class> customEditors =
            new HashMap, Class>(4);

设置到TypeConverter的属性

    private Map, 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 not thread-safe.
     * 

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.
     * 

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> entry : this.customEditors.entrySet()) { Class requiredType = entry.getKey(); Class 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.
     * 

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>

 

在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.
 *
 * 

Note: Since TypeConverter implementations are typically based on * {@link java.beans.PropertyEditor PropertyEditors} which aren't thread-safe, * TypeConverters themselves are not to be considered as thread-safe either. * * @author Juergen Hoeller * @since 2.0 * @see SimpleTypeConverter * @see BeanWrapperImpl */

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

你可能感兴趣的:(spring)