spring类型转换器(一)

2020-08-30  本文已影响0人  立志java

spring类型转换器(一)

在spring容器初始化的时候,BeanDefinition中配置的bean的属性值一般都为String类型,如何将String类型转换为Bean中属性对应的类型呢,在这个过程中就需要用到类型转换器了。spring实例化bean过程中对属性值的转换主要是使用BeanWrapperImpl实现的。

首先来看下BeanWrapperImpl的使用

@Data
public class TestBean {
    private Date birthday;
    private Dog dog;
    private ESex sex;
}

@Data
public class Dog {
    private String name;
    private Map<String,String> props;
    public Dog(){
        log.info("创建新的dog对象");
    }
    public Dog(String name){
        log.info("创建新的dog对象");
        this.name = name;
    }
}

@AllArgsConstructor
@Getter
public static enum ESex{
    MAlE(1),
    FAMALE(2);
    private int code;
}

定义一个处理日期的转换器

public class DatePropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = null;
            if(text != null) {
                date = sf.parse(String.valueOf(text));
            }
            super.setValue(date);
        } catch (ParseException e) {}
    }
}

创建一个BeanWrapperImpl用于包装目标bean(这里来模拟spring的内部实现)。然后注册Date类型的转换器,将值使用DatePropertyEditor转换为Date类型。调用setPropertyValue的时候,给testBean的birthday字段设置一个字符串类型的时间,在实际赋值的过程中会调用到类型转换器将字符串转换为日期类型。

TestBean testBean = new TestBean();
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(testBean);
//注册 当遇到对象属性类型为Date的时候,使用DatePropertyEditor对属性值进行处理
beanWrapper.registerCustomEditor(Date.class,new DatePropertyEditor());
beanWrapper.setPropertyValue("birthday","2018-11-29 12:12:12");//设置值
beanWrapper.setAutoGrowNestedPaths(true);//设置嵌套属性自动创建
beanWrapper.setPropertyValue("sex","MAlE");//将值根据枚举名字转换为枚举
beanWrapper.setPropertyValue("dog","小黑子");//将值直接作为 Dog构造函数的参数反射创建对象
beanWrapper.setPropertyValue("dog.props[color]","白色");//嵌套属性设置值
System.out.println(testBean.getBirthday());//Thu Nov 29 12:12:12 CST 2018

同样可以实现一个String trim的转换器

public class StringPropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if(text != null){
            text = text.trim();
        }
        super.setValue(text);
    }
}
//指定目标类型为String时,使用该转换器
beanWrapper.registerCustomEditor(String.class,new DatePropertyEditor());

BeanWrapper支持嵌套属性的赋值,当存在嵌套属性的时候需要设置 setAutoGrowNestedPaths=true。

表达式 含义
name 给属性name赋值,如果name是对象,将值作为该对象构造器的参数创建对象
bean.name 属性bean是一个对象,给对象bean中的name赋值,需设置
name[1] 属性类型为array、list,给第n个下标赋值
name{key} 属性为一个Map,指定key赋值,默认会创建LinkedHashMap

接下来我们就来研究一下BeanWrapperImpl的实现过程

属性编辑PropertyEditor

java.beans包中声明了一个PropertyEditor接口,用于提供对属性的访问和赋值。

public interface PropertyEditor {
    void setValue(Object value);//设置值
    Object getValue();//获取属性编辑器的值
    String getAsText();//获取转换为String类型的值
    void setAsText(String text) throws java.lang.IllegalArgumentException;//用于转换String类型
}

PropertyEditor有个默认实现类PropertyEditorSupport,如果要自定义属性转换器,直接继承该类,然后覆写setAsText、getAsText、setValue、getValue方法。在类型转换的时候如果值是字符串会调用setAsText来赋值value,其他情况下会调用setValue来赋值value,然后再调用getValue获取改变后的value值完成类型转换。相当于将PropertyEditor当做一个加工作坊,传进去一个值,返回想要类型的值

public class PropertyEditorSupport implements PropertyEditor {
    private Object value;
    public void setValue(Object value) {
        this.value = value;
        firePropertyChange();
    }
    public Object getValue() {
        return value;
    }
    public String getAsText() {
        return (this.value != null) ? this.value.toString() : null;
    }//覆盖实现
    public void setAsText(String text) throws java.lang.IllegalArgumentException {
        if (value instanceof String) {
            setValue(text);
            return;
        }
        throw new java.lang.IllegalArgumentException(text);
    }
}

注意:PropertyEditor是线程不安全的,有状态的,因此每次使用时都需要创建一个,不可重用;

BeanWrapper

首先先看下BeanWrapperImpl的继承图。还有一个跟BeanWrapperImpl平级的实现类DirectFieldAccessor,用于处理getter和setter的字段访问

image

从图可以看出,BeanWrapperImpl实现了3个顶级接口,提供了对象属性访问、类型转换器的注册和查找、类型转换功能

注册\查找类型转换器

从继承图可以看到PropertyEditorRegistrySupport实现了PropertyEditorRegistry接口,该类默认实现了类型转换器的注册和查找功能

在PropertyEditorRegistrySupport声明了多个存储结构用于存储不同的类型转换器来源。这里需要注意的是PropertyEditor是存在在Map中的,目标类型作为key,所以对于一个类型只能注册一个PropertyEditor,后面注册的会覆盖前面注册的

private ConversionService conversionService;//ConversionService转换器
private Map<Class<?>, PropertyEditor> defaultEditors;//自身默认创建的类型转换器
private Map<Class<?>, PropertyEditor> overriddenDefaultEditors;//
private Map<Class<?>, PropertyEditor> customEditors;//外界自定义添加的类型转换器
private Map<String, CustomEditorHolder> customEditorsForPath;//绑定字段名称的类型转换器
private Map<Class<?>, PropertyEditor> customEditorCache;//用于存储对应父类的类型转换器

同时还看到一个conversionService变量,spring提供了另一种类型转换接口Converter,通过conversionService调用对应的Converter进行类型转换,在PropertyEditorRegistrySupport同样可以注册进来conversionService,用于使用Converter进行类型转换。conversionService的详细使用会在下篇文章中讲到。

public void setConversionService(ConversionService conversionService) {
   this.conversionService = conversionService;
}

接下来来看PropertyEditor的注册过程。

public void registerCustomEditor(Class<?> requiredType, String propertyPath, PropertyEditor propertyEditor) {
   if (requiredType == null && propertyPath == null) {
      throw new IllegalArgumentException("Either requiredType or propertyPath is required");
   }
   //给属性名注册特定的类型转换器,添加到 customEditorsForPath
   if (propertyPath != null) {
      if (this.customEditorsForPath == null) {
         this.customEditorsForPath = new LinkedHashMap<String, CustomEditorHolder>(16);
      }//存储在customEditorsForPath
      this.customEditorsForPath.put(propertyPath, new CustomEditorHolder(propertyEditor, requiredType));
   } else { 注册自定义的类型转换器 添加到 customEditors
      if (this.customEditors == null) {
         this.customEditors = new LinkedHashMap<Class<?>, PropertyEditor>(16);
      }//存储在customEditors
      this.customEditors.put(requiredType, propertyEditor);
      this.customEditorCache = null;
   }
}

在上面提到过PropertyEditor存在在一个Map中,key是目标类型,那么这个参数propertyPath是干嘛的呢?这是为了给属性名指定专属的类型的转换器。因为一个目标类型只能有一个PropertyEditor的限制。但是有时候确实某个属性的类型转换比较特殊,这个时候就可以给这个属性名单独注册一个类型转换器,不会覆盖其他的哦。在类型转换的时候,会先根据属性名去customEditorsForPath中找可以用的PropertyEditor。

来看PropertyEditor的查找流程

image

首先根据属性名从customEditorsForPath查找特定的类型转换器

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>();
             //解析字段名, a.b[0]这种
            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) {
         //遍历已有的类型转换器,如果类型是requiredType的父类则使用该类型转换器
         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);
               if (this.customEditorCache == null) {//缓存起来
                  this.customEditorCache = new HashMap<Class<?>, PropertyEditor>();
               }
               this.customEditorCache.put(requiredType, editor);
            }
         }
      }
   }
   return editor;
}

PropertyEditorRegistrySupport 中默认添加了一些转换器,当调用 getDefaultEditor(requiredType)的时候会进行注册

public PropertyEditor getDefaultEditor(Class<?> requiredType) {
   if (!this.defaultEditorsActive) {
      return null;
   }
   if (this.defaultEditors == null) {
      createDefaultEditors(); //先注册默认的转换器
   }
   return this.defaultEditors.get(requiredType);//获取默认注册的类型转换器
}
private void createDefaultEditors() {
    this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64);
    this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
    this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
    this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
    this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
    this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
    this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
    //.....
}

类型转换

TypeConverter接口定义了将一个值转换为目标类型的值的功能。在继承图中可以看出TypeConverterSupport对类型转换提供了默认实现。

TypeConverterSupport将类型转换功能委托给typeConverterDelegate实现

@Override
public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
    return doConvert(value, requiredType, null, null);
}

private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field) throws TypeMismatchException {
    if (field != null) {
        return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
    }
    else {
        return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
    }
}

TypeConverterDelegate实现了类型转换的功能,创建TypeConverterDelegate的时候需要一个propertyEditorRegistry对象,用于查找匹配的类型转换器

public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry) {
   this(propertyEditorRegistry, null);
}
//转换功能
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
            Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
    //......
}
image

首先通过propertyEditorRegistry查找自定义的类型转换器PropertyEditor和ConversionService

PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();

当该类型没有注册自定义的PropertyEditor,并且存在conversionService的时候,使用conversionService进行类型转换。如果conversionService中没有配置对应的converter,那么继续尝试使用默认注册的PropertyEditor。

if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
   TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);//获取value的类型
   //判断conversionService是否配置了指定类型的converter,没有直接跳过,继续向下执行
   if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {//
      try {//使用conversionService完成类型转换
         return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
      }
      catch (ConversionFailedException ex) {
         // fallback to default conversion logic below
         conversionAttemptEx = ex;
      }
   }
}

如果目标类型存在自定义PropertyEditor 或者 目标类型和值类型不一样则需要进行类型转换(当没有找到ProperEditor的时候会尝试查找默认注册的PropertyEditor)

if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
    //目标类型是Collection子类的时候,将String类型的值先根据 , 分割为字符串数组
   if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
         convertedValue instanceof String) {
      TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
      if (elementTypeDesc != null) {
         Class<?> elementType = elementTypeDesc.getType();
          //将值转换为String数组
         if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
            convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
         }
      }
   }//editor不存在,查找PropertyEditorRegistrySupport中默认注册的类型转换器
   if (editor == null) {
      editor = findDefaultEditor(requiredType);
   }//使用 PropertyEditor进行类型转换
   convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}

类型转换,主要分三种情况处理,值类型不是字符串,值类型是字符串数组,值类型是字符串

private Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
    Object convertedValue = newValue;
    //当值不是String类型的时候,使用PropertyEditor的 setValue 和 getValue进行转换
    if (editor != null && !(convertedValue instanceof String)) {
        try {
            editor.setValue(convertedValue);
            Object newConvertedValue = editor.getValue();
            if (newConvertedValue != convertedValue) {
                convertedValue = newConvertedValue;
                //已完成类型转换,置为空,防止最后一步进行类型转换
                editor = null;
            }
        } catch (Exception ex) {
            //throw....
        }
    }

    Object returnValue = convertedValue;
    //当值为字符串数组,但是目标类型不是数组的时候,将值用,连接为字符串
    if (requiredType != null && !requiredType.isArray() && convertedValue instanceof String[])     {
        convertedValue = StringUtils.arrayToCommaDelimitedString((String[]) convertedValue);
    }
    //值为String类型,调用PropertyEditor的 setAsText进行转换
    if (convertedValue instanceof String) {
        if (editor != null) {
            // Use PropertyEditor's setAsText in case of a String value.
            String newTextValue = (String) convertedValue;
            return doConvertTextValue(oldValue, newTextValue, editor);
        } else if (String.class == requiredType) {
            returnValue = convertedValue;
        }
    }
    return returnValue;
}
//转换String类型的值,这里使用了oldValue触发属性改变事件并将原值传递给监听器。然后再设置新值
private Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
    try {
        editor.setValue(oldValue); //这里使用oldValue,用于触发属性改变事件
    } catch (Exception ex) {
        // Swallow and proceed.
    }//使用 setAsText 处理字符串类型的属性转换
    editor.setAsText(newTextValue);
    return editor.getValue();
}

最后,需要对转换后的值和目标类型进行判断,是否符合要求,如果不符合继续处理。这里主要处理了集合类型还有Number类型、基本类型转String、枚举类型。

if (requiredType != null) {
    if (convertedValue != null) {
        if (Object.class == requiredType) {
            return (T) convertedValue;
        } else if (requiredType.isArray()) {
            // Array required -> apply appropriate conversion of elements.
            if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
                convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
            }
            return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
        } else if (convertedValue instanceof Collection) {
            // Convert elements to target type, if determined.
            convertedValue = convertToTypedCollection(
                (Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
            standardConversion = true;
        }else if (convertedValue instanceof Map) {//值是map的时候,转换为 目标类型的map 
            convertedValue = convertToTypedMap(
                (Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
            standardConversion = true;
        }
        if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
            convertedValue = Array.get(convertedValue, 0);
            standardConversion = true;
        }//将基本类型 直接转换为String
        if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
            // We can stringify any primitive value...
            return (T) convertedValue.toString();
        } else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
            if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
                    //直接把值当做类型的构造函数的参数 反射创建目标类型对象
                    Constructor<T> strCtor = requiredType.getConstructor(String.class);
            }
            String trimmedValue = ((String) convertedValue).trim();
            if (requiredType.isEnum() && "".equals(trimmedValue)) {
                // It's an empty enum identifier: reset the enum value to null.
                return null;
            }//根据枚举名字 转换为枚举对象
            convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
            standardConversion = true;
        } else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {//转换number类型
            convertedValue = NumberUtils.convertNumberToTargetClass(
                (Number) convertedValue, (Class<Number>) requiredType);
            standardConversion = true;
        }
    }
    //如果使用editor转换失败,再次尝试使用conversionService进行转换
    if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
        TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
            if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
            }
    }
}

在attemptToConvertStringToEnum方法中自动根据枚举的名称转换为枚举的对象

Field enumField = requiredType.getField(trimmedValue);
ReflectionUtils.makeAccessible(enumField);
convertedValue = enumField.get(null);

属性访问

PropertyAccessor接口定义了属性访问的功能。通过实现setPropertyValue 和 getPropertyValue方法实现对象属性的赋值和访问。

AbstractPropertyAccessor实现了PropertyAccessor接口,不过没有对setPropertyValue和getPropertyValue进行实现,而是单独提供了一个 setPropertyValues的方法, 用于批量设置属性值,同时可以通过 ignoreUnknown和ignoreInvalid参数忽略未知的属性

public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) throws BeansException {
    List<PropertyAccessException> propertyAccessExceptions = null;
    List<PropertyValue> propertyValues = pvs instanceof MutablePropertyValues ? ((MutablePropertyValues)pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues());
    Iterator var6 = propertyValues.iterator();
    while(var6.hasNext()) {
        PropertyValue pv = (PropertyValue)var6.next();
        try {
            this.setPropertyValue(pv);//调用子类实现的setPropertyValue方法
        } catch (NotWritablePropertyException var9) {
            if (!ignoreUnknown) {
                throw var9;
            }
        } catch (NullValueInNestedPathException var10) {
            if (!ignoreInvalid) {
                throw var10;
            }
        }
    }
}

在AbstractNestablePropertyAccessor类中实现了setPropertyValue和getPropertyValue功能。

@Override
public void setPropertyValue(String propertyName, Object value) throws BeansException {
   AbstractNestablePropertyAccessor nestedPa;
   //用于解决 name.map[key] 类型的属性注入
   nestedPa = getPropertyAccessorForPropertyPath(propertyName);
   PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
   //为属性赋值
    nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
}

由于存在嵌套属性赋值的情况,对于嵌套的处理,其实只需要对嵌套的最底层进行类型转换,上层每一层就创建默认的值然后set到再上层对象的属性中。在这里spring使用了递归解决这个问题,创建每一层属性的对象值,使用BeanWrapper包装该对象,那么又是一个BeanWrapperImpl的赋值流程。

/**
* 例如 处理 beanWrapper.setPropertyValue("dog.props[color]","白色");
*/
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
   int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
  //递归发生在这里
   if (pos > -1) {
       //解析出最上层的属性名。
      String nestedProperty = propertyPath.substring(0, pos);//dog
      String nestedPath = propertyPath.substring(pos + 1);//剩下的属性路径 props[color]
       //针对最上层的属性 创建AbstractNestablePropertyAccessor 包装该对象并赋值
      AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
      //递归调用 直到完成 testBean注入了dog 返回对dog的包装,后续对dog的props属性处理
       return nestedPa.getPropertyAccessorForPropertyPath(nestedPath); //处理props属性注入
   } else {//不存在嵌套属性,直接返回自己,只需要对自己本身依赖的属性赋值
      return this;
   }
}

来看这个递归的内部实现,在getNestedPropertyAccessor完成对外层属性的初始化和将该值赋值到所依赖的对象中。然后使用BeanWrapper封装属性对象,后续走属性对象的赋值流程

private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
   if (this.nestedPropertyAccessors == null) {
      this.nestedPropertyAccessors = new HashMap<String, AbstractNestablePropertyAccessor>();
   }
   // Get value of bean property.
   PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
   String canonicalName = tokens.canonicalName;
   Object value = getPropertyValue(tokens);//获取对象中该属性的值
   if (value == null || (value.getClass() == javaUtilOptionalClass && OptionalUnwrapper.isEmpty(value))) {
      if (isAutoGrowNestedPaths()) {//设置允许自动创建嵌套属性
          //值为空,嵌套的都是对象,这里就是反射创建属性对象,并将该对象set到宿主对象中
         value = setDefaultValue(tokens);
      } else {//不允许的情况下 抛出异常 结束
         throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName);
      }
   }
   // Lookup cached sub-PropertyAccessor, create new one if not found.
   AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName);
   if (nestedPa == null || nestedPa.getWrappedInstance() !=
         (value.getClass() == javaUtilOptionalClass ? OptionalUnwrapper.unwrap(value) : value)) {
    //再次使用BeanWrapper包装 该属性对象,接下来就是对属性对象的递归赋值
      nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR);
      // 继承外层对象的类型转换器
      copyDefaultEditorsTo(nestedPa);
      copyCustomEditorsTo(nestedPa, canonicalName);
      this.nestedPropertyAccessors.put(canonicalName, nestedPa);
   }
   return nestedPa;
}

创建属性对象,并将该对象set到宿主对象。因为对象是指针引用的,所以在这步已经完成对宿主对象的属性赋值,接下来的流程只要对属性对象中的依赖属性进行赋值。

private Object setDefaultValue(PropertyTokenHolder tokens) {
   PropertyValue pv = createDefaultPropertyValue(tokens);//创建对应类型的默认值
   setPropertyValue(tokens, pv);
    //这里先set 然后再get 为了应用宿主对象中的类型转换器对值进行转换
   return getPropertyValue(tokens);
}

使用递归解决了嵌套赋值的问题,那么接下来就是针对最底层BeanWrapperImpl的属性赋值流程

protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
    if (tokens.keys != null) {//解决集合 map类型的赋值
        processKeyedProperty(tokens, pv);//解决 map[key]的情况
    } else {
        processLocalProperty(tokens, pv);//赋值
    }
}

在processLocalProperty方法中,首先通过子类获取属性处理器,通过PropertyHandler对属性赋值。在赋值之前再次判断属性是否已经进行了类型转换,如果没有再次调用类型转换器进行转换,如果已经完成类型转换,使用ConvertedValue

PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);//子类提供的钩子方法
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
    if (pv.isConverted()) {//如果已经完成类型转换,取类型转换后的值
        valueToApply = pv.getConvertedValue();
    } else {//未完成类型转换的,再次调用类型转换器进行转换
        valueToApply = convertForProperty(
            tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
    }
    pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
ph.setValue(this.wrappedObject, valueToApply);

对属性的访问和设置spring进行了更小粒度的封装。提供了 PropertyHandler抽象类。为什么在这里进行抽象,看PropertyHandler的两个实现,可以看到一个是BeanPropertyHandler,一个是FieldPropertyHandler,不难想象,属性一种是由getter和setter方法进行访问,一种是没有getter和setter直接反射字段进行的。

如果要对map进行控制,我们可以再提供一个专门处理map的实现了类handler

//定义在父类中的内部抽象类
protected abstract static class PropertyHandler {
    private final Class<?> propertyType;
    private final boolean readable;
    private final boolean writable;
    public abstract Object getValue() throws Exception;
    public abstract void setValue(Object object, Object value) throws Exception;
}

BeanWrapperImpl提供了BeanPropertyHandler,将setter和getter传入

@Override
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
    //反射获取
   PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
   return (pd != null ? new BeanPropertyHandler(pd) : null);
}

BeanPropertyHandler提供对setter和getter的访问

private class BeanPropertyHandler extends PropertyHandler {
   private final PropertyDescriptor pd;
   @Override
   public ResolvableType getResolvableType() {
      return ResolvableType.forMethodReturnType(this.pd.getReadMethod());
   }

   @Override
   public Object getValue() throws Exception {
      final Method readMethod = this.pd.getReadMethod();
      return readMethod.invoke(getWrappedInstance(), (Object[]) null);
   }
   @Override
   public void setValue(final Object object, Object valueToApply) throws Exception {
       final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
                                   ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
                                   this.pd.getWriteMethod());

       writeMethod.invoke(getWrappedInstance(), value);
   }
}

AbstractNestablePropertyAccessor的另一个实现类DirectFieldAccessor,专门用于给字段赋值,不依赖setter和getter,那么这个是怎么实现的,看源码发现是DirectFieldAccessor中提供了一个PropertyHandler的实现类,通过Field的反射实现了setValue和getValue

private class FieldPropertyHandler extends PropertyHandler {
   private final Field field;

   public FieldPropertyHandler(Field field) {
      super(field.getType(), true, true);
      this.field = field;
   }
   @Override
   public Object getValue() throws Exception {
       return this.field.get(getWrappedInstance());
   }
   @Override
   public void setValue(Object object, Object value) throws Exception {
            this.field.set(object, value);
   }
}
上一篇 下一篇

猜你喜欢

热点阅读