PropertyEditor最早用于Swing编程中,在Spring中主要被用于xml内value的转换和mvc中参数值得转换。
Spring容器在applyPropertyValues通过TypeConverter对value进行值得转换,具体的调用栈如下
createBean->doCreateBean->populateBean->applyPropertyValues
具体的转换代码如下
private Object convertForProperty(Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
if (converter instanceof BeanWrapperImpl) {
return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
}
else {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
}
}
从源码可以看出当customTypeConverter为空是,将会使用BeanWrapper进行转换,因为BeanWrapper实现了PropertyEditorRegistry接口。
现在讲讲如何配置自定义的PropertyEditor, 通过配置CustomEditorConfigurer代码如下
CustomEditorConfigurer本质上是一个BeanFactoryPostProcessor, 所以在初始化容器之后,会通过ConfigurableListableBeanFactory的addPropertyEditorRegistrar和registerCustomEditor, 将其自身配置的propertyEditorRegistrars和customEditors添加到容器中。那么就到了下一步,如果使用这些最后都变成PropertyEditor并且用于转换value为对应类型的object。
customEditors, propertyEditorRegistrars, typeConverter, conversionService
typeConverter内部结合了conversionService和PropertyEditor来转换值,
conversionService是spring3.0新加的用于转换的接口和PropertyEditor属于一个性质的东西。
之前说到BeanWrapper是一个实现了PropertyEditorRegistry的接口,其内部有很多的PropertyEditor,这些editor则是通过beanFactory的initBeanWrapper注册到beanwrapper当中的,代码如下:
/**
* Initialize the given BeanWrapper with the custom editors registered
* with this factory. To be called for BeanWrappers that will create
* and populate bean instances.
* The default implementation delegates to {@link #registerCustomEditors}.
* Can be overridden in subclasses.
* @param bw the BeanWrapper to initialize
*/
protected void initBeanWrapper(BeanWrapper bw) {
bw.setConversionService(getConversionService());
registerCustomEditors(bw);
}
/**
* 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()) {
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
try {
registrar.registerCustomEditors(registry);
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
"] failed because it tried to obtain currently created bean '" +
ex.getBeanName() + "': " + ex.getMessage());
}
onSuppressedException(ex);
continue;
}
}
throw ex;
}
}
}
if (!this.customEditors.isEmpty()) {
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));
}
}
}
所以每一个BeanWrapper相当于都从BeanFactory中获取PropertyEditor,最终用于值转换,
对于BeanFactory而言,则在AbstractApplicationContext的prepareBeanFactory中添加一个ResourceEditorRegistrar。代码如下
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}