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 extends PropertyEditor>> customEditors =
new HashMap, Class extends PropertyEditor>>(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 extends PropertyEditor>> entry : this.customEditors.entrySet()) {
Class> requiredType = entry.getKey();
Class extends PropertyEditor> editorClass = entry.getValue();
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass));
}
}
}
下面看一下在beanFactory中是如何设置customEditors,propertyEditorRegistrars,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属性中。
我们知道如果要设置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()));
在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方法一样。