[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
只要設置一個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屬性中。
咱們知道若是要設置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方法同樣。