spring中TypeConverter对象解析

[TOC] ###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方法一样。

转载于:https://my.oschina.net/u/2298333/blog/656004

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值