spring中TypeConverter對象解析

[TOC] ###TypeConverter在同期容器中的建立及初始化 spring的容器中有不少地方會用的類型轉換,spring使用TypeConverter作類型轉換,如今咱們來分析TypeConverter是如何在spring的容器中使 在AbstractBeanFactory對象下面定義了屬性typeConverter,代碼以下:java

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

會覆蓋默認PropertyEditor機制,該對象能夠設置一個自定義的對象,若是沒有設置,會使用SimpleTypeConverter做爲默認實現類, 同時會將beanFatory中定義的兩個屬性spring

/** 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定義的屬性app

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

設置到TypeConverter的屬性編輯器

private ConversionService conversionService;

中,獲取該對象的相關方法以下:ide

方法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:post

/**
     * 初始化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對象的。ui

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方法同樣。

相關文章
相關標籤/搜索