spring功能扩展-增加属性编辑器(2)
上篇文章通过一个例子描述了如何改变User实例中birthday属性的类型,现在重温下大概过程:
① 定义属性编辑器 DatePropertyEditor
② 实例化 CustomEditorConfigurer 并将 DatePropertyEditor 实例添加到 customEditors 属性中
查看上篇中 CustomEditorConfigurer 源码可以发现它除了有customEditors属性,还有 propertyEditorRegistrars 属性,在本篇中将描述PropertyEditorRegistrar 的用法
@Nullable
private PropertyEditorRegistrar[] propertyEditorRegistrars;
@Nullable
private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;
PropertyEditorRegistrar 使用方法
PropertyEditorRegistrar 解释
PropertyEditorRegistrar (属性编辑注册器),这是一个接口,顾名思义这个接口是用来注册属性编辑器的,以下是源码及官方解释
package org.springframework.beans;
/**
* Interface for strategies that register custom
* {@link java.beans.PropertyEditor property editors} with a
* {@link org.springframework.beans.PropertyEditorRegistry property editor registry}.
*
* <p>This is particularly useful when you need to use the same set of
* property editors in several different situations: write a corresponding
* registrar and reuse that in each case.
*
* @author Juergen Hoeller
* @since 1.2.6
* @see PropertyEditorRegistry
* @see java.beans.PropertyEditor
*/
public interface PropertyEditorRegistrar {
/**
* Register custom {@link java.beans.PropertyEditor PropertyEditors} with
* the given {@code PropertyEditorRegistry}.
* <p>The passed-in registry will usually be a {@link BeanWrapper} or a
* {@link org.springframework.validation.DataBinder DataBinder}.
* <p>It is expected that implementations will create brand new
* {@code PropertyEditors} instances for each invocation of this
* method (since {@code PropertyEditors} are not threadsafe).
* @param registry the {@code PropertyEditorRegistry} to register the
* custom {@code PropertyEditors} with
*/
void registerCustomEditors(PropertyEditorRegistry registry);
}
如上所示PropertyEditorRegistrar 接口只有一个 registerCustomEditors方法,入参为 PropertyEditorRegistry 类型,PropertyEditorRegistry也是一个接口,上文中BeanWrapperImpl实例就实现了这个接口
PropertyEditorRegistrar 实现类定义
以下为自定义PropertyEditorRegistrar属性编辑注册器 DatePropertyEditorRegistrar的 代码:
package com.springtest.propertyEditor;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
在 registerCustomEditor方法中使用了spring 自带的PropertyEditor CustomDateEditor,在上文中我们也可以使用这个CustomDateEditor,只是为了 讲解PropertyEditor 和 PropertyEditorSupport 而重现实现了一遍。
在CustomEditorConfigurer 实例中添加 DatePropertyEditorRegistrar
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="com.springtest.propertyEditor.DatePropertyEditorRegistrar"></bean>
</list>
</property>
</bean>
PropertyEditorRegistrar 使用方式步骤如上
PropertyEditorRegistrar 执行过程
回到 AbstractBeanFactory registerCustomEditors 方法,这个方法是在填充 BeanWrapper 实例时调用的,在上文中我们给beanFactory填充的是customEditors属性,所以 propertyEditorRegistrars中不会有我们自定义的PropertyEditorRegistrar ,进而执行 if (!this.customEditors.isEmpty()) 中的代码块,看if代码块中具体内容 registry.registerCustomEditor ,和PropertyEditorRegistrar 实现类DatePropertyEditorRegistrar 中registerCustomEditors方法中的内容一致,而PropertyEditorRegistrar 接口registerCustomEditors方法的调用时机则是在 if (!this.propertyEditorRegistrars.isEmpty()) 代码块中
protected void initBeanWrapper(BeanWrapper bw) {
bw.setConversionService(getConversionService());
registerCustomEditors(bw);
}
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;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {
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()) {
this.customEditors.forEach((requiredType, editorClass) ->
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
}
}
细看两种改变属性值的方式,其实是差不多的,反倒实现PropertyEditorRegistrar 接口的方式好像还多了一个额外注册属性编辑器的动作