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