Spring 源码个人浅浅分析(6)--- 功能可扩展之属性注册编辑器ResourceEditorRegistrar
ApplicationContext包含了BeanFactory的所有功能,并且对此也扩展了很多功能。
在方法ObtainFreshBeanFactory中,基本已经解析并注册了所有xml中的bean,且可以对bean的获取以及基本使用了。而在方法prepareBeanFactory中,也正是applicationContext在功能上的扩展由此展开。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
//设置beanFactory的表达式语言处理器,spring 3增加了表达式语言的支持
//默认可以使用#{bean.xxx}的形式来调用相关的属性
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
//为beanFactory增加一个默认的propertyEditor,这个主要是对bean的属性等设置管理一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
// 添加BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//设置了几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.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);
// Detect a LoadTimeWeaver and prepare for weaving, if found.
//增加了对AspectJ的支持
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.
//添加默认的系统环境bean
if (!beanFactory.containsBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
注册了属性编辑器bean,ResourceEditorRegistrar类
进入ResourceEditorRegistrar,主要方法 registerCustomEditor
public void registerCustomEditors(PropertyEditorRegistry registry) {
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
doRegisterEditor(registry, Resource.class, baseEditor);
doRegisterEditor(registry, ContextResource.class, baseEditor);
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
ClassLoader classLoader = this.resourceLoader.getClassLoader();
doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
if (this.resourceLoader instanceof ResourcePatternResolver) {
doRegisterEditor(registry, Resource[].class,
new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
}
}
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
if (registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
}
else {
registry.registerCustomEditor(requiredType, editor);
}
}
主要是提前注册简单通用常用类型的属性编辑器
那么是在什么时候开始进行注册的呢?
查看类方法的调用情况
可以看到在AbstractBeanFactory中调用到这个方法,
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<?>, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) {
Class<?> requiredType = entry.getKey();
Class<? extends PropertyEditor> editorClass = entry.getValue();
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass));
}
}
}
通过上面的方法,对propertyEditorRegistrars 进行遍历,逐一调用registerCustomEditors方法进行注册,还有另一种自定义的编辑器customEditors,遍历且注册类型编辑器。
继续查看AbstarctBeanFactory类。
可以看到是在AbsractBeanFactory的initBeanWrapper方法,这是在bean实例化的时候,在beanDefinition转换为BeanWrapper后用于对属性的填充。
以BeanWrapper作为registerCustomEditors方法的入参,查看原因,BeanWrapper间接的继承了PropertyEditorRegister类型。
在spring DI注入的时候可以把普通属性注入进来,但是像Date类型就无法被识别,例如配置文件配置。
<bean id="demoBean" class="springSourseAnalyes.BeanA" scope="singleton" init-method="init" lazy-init="true" >
<property name="date" value="2018-08-22" />
<property name="nameString" value="崔春驰" />
<!-- <property name="b" ref="b" /> -->
</bean>
如果这样直接使用,程序就会报错,报类型转换异常,不成功。
spring针对此问题提供了两种解决方法
1、使用自定义属性编辑器
使用自定义属性编辑器,通过继承PropertyEditorSupport,重写setAsText方法。
(1)编写自定义的属性编辑器
package springSourseAnalyes;
import java.beans.PropertyEditorSupport;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
/**
* 自定义属性编辑器 因为日期date型的注入会出现问题,没法转型
* 重新复写setAsText方法
*
* 当注入的时候遇到Date时,就会使用自定义的属性编辑器
*
* 两种方式:1:继承PropertyEditorSupport类
* 2:实现PropertyEditorRegistrar接口
*
* 在xml配置文件配置CustomEditorConfigurer的class类,其实现了BeanFactoryPostProcessor
* <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" >
<bean class="springSourseAnalyes.DatePropertyEditor" >
<property name="format" value="yyyy-MM-dd" />
</bean>
</entry>
</map>
</property>
</bean>
* @author MTW
*
*/
public class DatePropertyEditor extends PropertyEditorSupport {
private String format = "yyyy-MM-dd";
public void setFormat(String format) {
this.format = format;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
// TODO Auto-generated method stub
System.out.println("属性:"+text);
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
try {
Date date = dateFormat.parse(text);
this.setValue(date);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage()+"抛出异常。。。。。");
}
}
}
(2) 将自定义的属性编辑器注册到spring中
<!-- 将自定义的属性编辑器注册到spring中 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" >
<bean class="springSourseAnalyes.DatePropertyEditor" >
<property name="format" value="yyyy-MM-dd" />
</bean>
</entry>
</map>
</property>
</bean>
2、注册Spring自带的属性b编辑器CustomDateEditor
通过注册Spring自带的属性编辑器CustomDateEditor,
package springSourseAnalyes;
import java.beans.PropertyEditorSupport;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
/**
* 自定义属性编辑器 因为日期date型的注入会出现问题,没法转型
* 重新复写setAsText方法
*
* 当注入的时候遇到Date时,就会使用自定义的属性编辑器
*
* 两种方式:1:继承PropertyEditorSupport类
* 2:实现PropertyEditorRegistrar接口
*
* 在xml配置文件配置CustomEditorConfigurer的class类,其实现了BeanFactoryPostProcessor
* <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" >
<bean class="springSourseAnalyes.DatePropertyEditor" >
<property name="format" value="yyyy-MM-dd" />
</bean>
</entry>
</map>
</property>
</bean>
或者第二种 使用常用的属性编辑器CustomDateEditor
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="springSourseAnalyes.DatePropertyEditorRegistrar" />
</list>
</property>
</bean>
* @author MTW
*
*/
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar{
/**
* CustomDateEditor 其实就是继承PropertyEditorSupport
*/
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
配置文件:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="springSourseAnalyes.DatePropertyEditorRegistrar" />
</list>
</property>
</bean>
通过将DatePropertyEditorRegistrar注入propertyEditorRefistrars属性中,也能达到相应的结果。
在配置文件引入类型为org.springframework.beans.factory.config.CustomEditorConfigurer的bean,并在属性customEditors中加入自定义的属性编辑器,其中key为属性编辑器所对应的类型。通过这样的配置,当Spring在注入bean的属性时一旦遇到 了java.util.Date类型的属性会自动调用自定义的DatePropertyEditor解析器进行解析,并用解析结果代替配置属性进行注入。
查看CustomEditorConfigurer类
package org.springframework.beans.factory.config;
import java.beans.PropertyEditor;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.PropertyEditorRegistrySupport;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
public class CustomEditorConfigurer implements BeanFactoryPostProcessor, BeanClassLoaderAware, Ordered {
protected final Log logger = LogFactory.getLog(getClass());
private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered
private PropertyEditorRegistrar[] propertyEditorRegistrars;
private Map<String, ?> customEditors;
private boolean ignoreUnresolvableEditors = false;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return this.order;
}
public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) {
this.propertyEditorRegistrars = propertyEditorRegistrars;
}
public void setCustomEditors(Map<String, ?> customEditors) {
this.customEditors = customEditors;
}
public void setIgnoreUnresolvableEditors(boolean ignoreUnresolvableEditors) {
this.ignoreUnresolvableEditors = ignoreUnresolvableEditors;
}
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
@SuppressWarnings("unchecked")
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//这个两种实现方式
//如果实现PropertyEditorRegistrar接口,则以这种方式注册属性编辑器
if (this.propertyEditorRegistrars != null) {
for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
}
}
//如果是继承PropertyEditorSupport ,并重写setAsText,且在配置xml中设置key--value
if (this.customEditors != null) {
for (Map.Entry<String, ?> entry : this.customEditors.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
Class requiredType = null;
try {
requiredType = ClassUtils.forName(key, this.beanClassLoader);
if (value instanceof PropertyEditor) {
if (logger.isWarnEnabled()) {
logger.warn("Passing PropertyEditor instances into CustomEditorConfigurer is deprecated: " +
"use PropertyEditorRegistrars or PropertyEditor class names instead. " +
"Offending key [" + key + "; offending editor instance: " + value);
}
beanFactory.addPropertyEditorRegistrar(
new SharedPropertyEditorRegistrar(requiredType, (PropertyEditor) value));
}
else if (value instanceof Class) {
beanFactory.registerCustomEditor(requiredType, (Class) value);
}
else if (value instanceof String) {
Class editorClass = ClassUtils.forName((String) value, this.beanClassLoader);
Assert.isAssignable(PropertyEditor.class, editorClass);
beanFactory.registerCustomEditor(requiredType, (Class<? extends PropertyEditor>) editorClass);
}
else {
throw new IllegalArgumentException("Mapped value [" + value + "] for custom editor key [" +
key + "] is not of required type [" + PropertyEditor.class.getName() +
"] or a corresponding Class or String value indicating a PropertyEditor implementation");
}
}
catch (ClassNotFoundException ex) {
if (this.ignoreUnresolvableEditors) {
logger.info("Skipping editor [" + value + "] for required type [" + key + "]: " +
(requiredType != null ? "editor" : "required type") + " class not found.");
}
else {
throw new FatalBeanException(
(requiredType != null ? "Editor" : "Required type") + " class not found", ex);
}
}
}
}
}
/**
* PropertyEditorRegistrar that registers a (deprecated) shared editor.
*/
private static class SharedPropertyEditorRegistrar implements PropertyEditorRegistrar {
private final Class requiredType;
private final PropertyEditor sharedEditor;
public SharedPropertyEditorRegistrar(Class requiredType, PropertyEditor sharedEditor) {
this.requiredType = requiredType;
this.sharedEditor = sharedEditor;
}
public void registerCustomEditors(PropertyEditorRegistry registry) {
if (!(registry instanceof PropertyEditorRegistrySupport)) {
throw new IllegalArgumentException("Cannot registered shared editor " +
"on non-PropertyEditorRegistrySupport registry: " + registry);
}
((PropertyEditorRegistrySupport) registry).registerSharedEditor(this.requiredType, this.sharedEditor);
}
}
}
该类实现了BeanFactoryPostProcessor,是对ConfigurableListableBeanFactory的功能扩展或修改等操作,这个类对于自定义属性编辑器很重要,是一个总入口。
这个两种实现方式
1、如果实现PropertyEditorRegistrar接口,则以这种方式注册属性编辑器
2、如果是继承PropertyEditorSupport ,并重写setAsText,且在配置xml中设置key--value
类型转换的使用:
在实例化后,已经将自定义以及常用的类型属性编辑器注册到了ConfigurableListenableBeanFactory中。下面就是在初始化中为属性填充数据的时候来开始调用类型自定义的类型转换,
思想:根据value的类型requireType来从缓存customEditors获取,如果没有这个类型对应的类型转换编辑器,则直接返回null。如果返回有编辑器,则使用自定义的类型转换编辑器去处理值。
在AbstractAutowireCapableBeanFactory的填充属性方法中:
protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
...
//属性填充
applyPropertyValues(beanName, mbd, bw, pvs);
}
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (System.getSecurityManager()!= null) {
if (bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
}
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
//获取属性name
String propertyName = pv.getName();
//获取属性value
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
//这段可以忽略使用类型转换
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
//类型转换,如果有自定义的,则用自定义的去转换类型
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
//设置属性值,填充类型转换后的值
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
convertForProperty方法是转换属性,调用自定义的来转换。
主要是在类TypeConverterDelegate类型转换委派中进行逻辑简单实现:
1、获取自定义属性编辑器类。
2、执行将原先的value来进行转换。
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
Object convertedValue = newValue;
// Custom editor for this type?
//获取自定义属性编辑器
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException firstAttemptEx = null;
.......省略
// Value not of required type?
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
if (editor == null) {
editor = findDefaultEditor(requiredType, typeDescriptor);
}
//去执行执行类型转换
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
......省略
return (T) convertedValue;
}
doConcertValue方法去执行类型转换。
protected Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
Object convertedValue = newValue;
boolean sharedEditor = false;
if (editor != null) {
sharedEditor = this.propertyEditorRegistry.isSharedEditor(editor);
}
if (editor != null && !(convertedValue instanceof String)) {
// Not a String -> use PropertyEditor's setValue.
// With standard PropertyEditors, this will return the very same object;
// we just want to allow special PropertyEditors to override setValue
// for type conversion from non-String values to the required type.
try {
Object newConvertedValue;
if (sharedEditor) {
// Synchronized access to shared editor instance.
synchronized (editor) {
editor.setValue(convertedValue);
newConvertedValue = editor.getValue();
}
}
else {
// Unsynchronized access to non-shared editor instance.
editor.setValue(convertedValue);
newConvertedValue = editor.getValue();
}
if (newConvertedValue != convertedValue) {
convertedValue = newConvertedValue;
// Reset PropertyEditor: It already did a proper conversion.
// Don't use it again for a setAsText call.
editor = null;
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
}
// Swallow and proceed.
}
}
Object returnValue = convertedValue;
.....省略
if (convertedValue instanceof String) {
if (editor != null) {
// Use PropertyEditor's setAsText in case of a String value.
if (logger.isTraceEnabled()) {
logger.trace("Converting String to [" + requiredType + "] using property editor [" + editor + "]");
}
String newTextValue = (String) convertedValue;
if (sharedEditor) {
// Synchronized access to shared editor instance.
synchronized (editor) {
//真正去执行自定义类型转换
return doConvertTextValue(oldValue, newTextValue, editor);
}
}
else {
// Unsynchronized access to non-shared editor instance.
return doConvertTextValue(oldValue, newTextValue, editor);
}
}
else if (String.class.equals(requiredType)) {
returnValue = convertedValue;
}
}
return returnValue;
}
最终调用doConvertTextValue方法
protected Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
try {
editor.setValue(oldValue);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
}
// Swallow and proceed.
}
//调用重写的setAstext方法
editor.setAsText(newTextValue);
return editor.getValue();
}
重类结构图的继承关系来看,,只需要继承PropertyEditorSupport,并且重写setAsText方法,转换后的值 调用setValue,因为value是共享变量,故为了线程安全,在调用时,使用了synchronized来加显示锁。
在类PropertyEditorRegistrySupport中,主要是获取自定义的属性编辑器。
/**
查找自定义的属性编辑器
*/
public PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath) {
Class<?> requiredTypeToUse = requiredType;
if (propertyPath != null) {
if (this.customEditorsForPath != null) {
// Check property-specific editor first.
PropertyEditor editor = getCustomEditor(propertyPath, requiredType);
if (editor == null) {
List<String> strippedPaths = new LinkedList<String>();
addStrippedPropertyPaths(strippedPaths, "", propertyPath);
for (Iterator<String> it = strippedPaths.iterator(); it.hasNext() && editor == null;) {
String strippedPath = it.next();
editor = getCustomEditor(strippedPath, requiredType);
}
}
if (editor != null) {
return editor;
}
}
if (requiredType == null) {
requiredTypeToUse = getPropertyType(propertyPath);
}
}
// No property-specific editor -> check type-specific editor.
return getCustomEditor(requiredTypeToUse);
}
/**
获取自定义的属性编辑器,用于类型转换
*/
private PropertyEditor getCustomEditor(Class<?> requiredType) {
if (requiredType == null || this.customEditors == null) {
return null;
}
// Check directly registered editor for type.
PropertyEditor editor = this.customEditors.get(requiredType);
if (editor == null) {
// Check cached editor for type, registered for superclass or interface.
if (this.customEditorCache != null) {
editor = this.customEditorCache.get(requiredType);
}
if (editor == null) {
// Find editor for superclass or interface.
for (Iterator<Class<?>> it = this.customEditors.keySet().iterator(); it.hasNext() && editor == null;) {
Class<?> key = it.next();
if (key.isAssignableFrom(requiredType)) {
editor = this.customEditors.get(key);
// Cache editor for search type, to avoid the overhead
// of repeated assignable-from checks.
if (this.customEditorCache == null) {
this.customEditorCache = new HashMap<Class<?>, PropertyEditor>();
}
this.customEditorCache.put(requiredType, editor);
}
}
}
}
return editor;
}
以上就是对spring的扩展属性编辑器即类型转换的源码理解
上一篇: SkipList的C语言完整实现