以前写了一篇介绍了BeanWrapperImpl整体结构,这篇就介绍其的一些细节,看其具体是怎样整合对象(wrappedObject--还未进行属性赋值的Bean对象)、属性(Property)、Converter/PropertyEditer(类型转换器),来完成对对象属性赋值的。

    接口介绍:

               

这里的TypeConverterSupport(类型转换)已经在上一篇讲过了,现在我们来看下关于类型转换操作的对象PropertyAccessor接口以及BeanWrapper。

     PropertyAccessor:

                  

   通过方法的名称可以知道,这个接口是通过Property的名称去设置Property的值,以及通过名称获取对应Property的Value的。而下面那些描叙符是用于划分,获取真正的Property的name的。这个到下面具体的流程介绍就明白了。

  BeanWrapper:

public interface BeanWrapper extends ConfigurablePropertyAccessor {
   void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
   int getAutoGrowCollectionLimit();

   /**
    * Return the bean instance wrapped by this object.
    */
   Object getWrappedInstance();
   /**
    * Return the type of the wrapped bean instance.
    */
   Class<?> getWrappedClass();

   PropertyDescriptor[] getPropertyDescriptors();
   PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
}

这个就是放Bean对象的接口,要注意标粗的两个方法。一个是获取设置的对象getWrappedInstance(),一个是获取这个对象的Class描叙getWrappedClass()。

 

   BeanWrapperImp整个操作过程

现在我们来看下BeanWrapperImp整个操作过程:

        AbstractNestablePropertyAccessor:

           我们先来看实现类型转换接口与属性设置接口的抽象类AbstractNestablePropertyAccessor,我们先来看其在Spring源码中的测试demo,这个类是抽象类,有些方法需要其子类去实现,所以我们需要结合其子类BeanWrapperImpl一起来梳理其流程:

@Test
public void getNestedProperty() {
   Person target = createPerson("John", "London", "UK");
   AbstractPropertyAccessor accessor = createAccessor(target);
   assertThat(accessor.getPropertyValue("address.city"), is("London"));
}
private Person createPerson(String name, String city, String country) {
   return new Person(name, new Address(city, country));
}
private static class Person {
   private String name;
   private Address address;
   private Person(String name, Address address) {
      this.name = name;
      this.address = address;
   }
........
}
private static class Address {
   private String city;
   private Country country;
   ........
}
protected BeanWrapperImpl createAccessor(Object target) {
   return new BeanWrapperImpl(target);
}

AbstractNestablePropertyAccessor的初始化方法有一个传Object:

protected AbstractNestablePropertyAccessor(Object object) {
   registerDefaultEditors();
   setWrappedInstance(object);
}
public void setWrappedInstance(Object object, @Nullable String nestedPath, @Nullable Object rootObject) {
   this.wrappedObject = ObjectUtils.unwrapOptional(object);
   Assert.notNull(this.wrappedObject, "Target object must not be null");
   this.nestedPath = (nestedPath != null ? nestedPath : "");
   this.rootObject = (!"".equals(this.nestedPath) ? rootObject : this.wrappedObject);
   this.nestedPropertyAccessors = null;
   this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
}

这里就是注册默认的PropertyEdier。然后setWrappedInstance,这个就是为Bean对象。

   现在这个AbstractNestablePropertyAccessor对象是Persion:

                

   getPropertyValue方法

   然后回到 accessor.getPropertyValue("address.city"),这个address.city,表示的就是去获取Person对象的的address属性对象的city属性的值。这个等下看其是怎样解析的。

public Object getPropertyValue(String propertyName) throws BeansException {
   AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName);
   PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
   return nestedPa.getPropertyValue(tokens);
}
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
   int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
   // Handle nested properties recursively.
   if (pos > -1) {
      String nestedProperty = propertyPath.substring(0, pos);
      String nestedPath = propertyPath.substring(pos + 1);
      AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
      return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
   }
   else {
      return this;
   }
}

这里的getFirstNestedPropertySeparatorIndex,就是处理前面的属性名称address.city的。我们最开始在前面讲PropertyAccessor接口有说其的一些描叙符:"."、"["、"]"等。如果是直接写的属性名,如Persion的name属性,就会返回-1,直接就返回当前AbstractNestablePropertyAccessor对象,this。如果有类型嵌套结构,就返回嵌套分割位置,再进一步处理:

 

private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
   ............
   // Get value of bean property.
   PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
   String canonicalName = tokens.canonicalName;
   Object value = getPropertyValue(tokens);
   ........
}
protected static class PropertyTokenHolder {
   ..........
   public String actualName;
   public String canonicalName;
   @Nullable
   public String[] keys;
}

这个PropertyTokenHolder接收用来放描叙PropertyName的,这里有个属性keys,就是用来放集合的index的,通过例子就能很好的了解描叙符与这个了:

private static class Foo {
   private List list;
}
accessor.setPropertyValue("list[0]", map);

                        

我们再回到getNestedPropertyAccessor方法,获取PropertyTokenHolder后,进入getPropertyValue方法:

protected Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
   String propertyName = tokens.canonicalName;
   String actualName = tokens.actualName;
   PropertyHandler ph = getLocalPropertyHandler(actualName);
   if (ph == null || !ph.isReadable()) {
      throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);
   }
   try {
      Object value = ph.getValue();
      if (tokens.keys != null) {
         if (value == null) {
            if (isAutoGrowNestedPaths()) {
               value = setDefaultValue(new PropertyTokenHolder(tokens.actualName));
            }
           ............
         }
         String indexedPropertyName = tokens.actualName;
         // apply indexes and map keys
         for (int i = 0; i < tokens.keys.length; i++) {
             ..........处理集合类型内容
         }
      }
      return value;
   }
}

这里的是getLocalPropertyHandler是AbstractNestablePropertyAccessor的抽象方法,其在BeanWrapperImp的实现:

protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
   PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
   if (pd != null) {
      return new BeanPropertyHandler(pd);
   }
   return null;
}
private CachedIntrospectionResults getCachedIntrospectionResults() {
   if (this.cachedIntrospectionResults == null) {
      this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass());
   }
   return this.cachedIntrospectionResults;
}
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
   ............
   results = new CachedIntrospectionResults(beanClass);
    ...........
   return (existing != null ? existing : results);
}
private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
      ...........
      this.beanInfo = getBeanInfo(beanClass, shouldIntrospectorIgnoreBeaninfoClasses);
      this.propertyDescriptorCache = new LinkedHashMap<>();
      PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
      for (PropertyDescriptor pd : pds) {
         .................
         this.propertyDescriptorCache.put(pd.getName(), pd);
}
public PropertyDescriptor[] getPropertyDescriptors() {
    return properties;
}

初次进入调用CachedIntrospectionResults.forClass(getWrappedClass()),这个getWrappedClass就是获取在初始化AbstractNestablePropertyAccessor的时候传的wrappedObject,这里获取其的Class描叙。然后通过这个beanClass去创建beanInfo,这个BeanInfo就是表示这个Bean的Class有哪些Property以及Method方法:

    然后循环这个BeanInfo的Property,将其添加到propertyDescriptorCache 中(这个propertyDescriptorCache 是CachedIntrospectionResults类的成员变量。

   再回到BeanWrapperImp实现的getLocalPropertyHandler方法,现在初始化设置了CachedIntrospectionResults对象,就调用其getPropertyDescriptor方法,通过PropertyName获取前面放在propertyDescriptorCache对应的PropertyDescriptor了。

public class PropertyDescriptor extends FeatureDescriptor {
    .........
    private final MethodRef readMethodRef = new MethodRef();
    private final MethodRef writeMethodRef = new MethodRef();
    ...........
    private String baseName;
    private String writeMethodName;
    private String readMethodName;
}

这个直接看其变量名就可以知道这个类是描叙Property及其对应的write、read方法。

PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName); 
  
PropertyDescriptor getPropertyDescriptor(String name) {
   PropertyDescriptor pd = this.propertyDescriptorCache.get(name);
   if (pd == null && StringUtils.hasLength(name)) {
      pd = this.propertyDescriptorCache.get(StringUtils.uncapitalize(name));
      if (pd == null) {
         pd = this.propertyDescriptorCache.get(StringUtils.capitalize(name));
      }
   }
   return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
         buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
}

获取到PropertyDescriptor后就运行:

if (pd != null) {
   return new BeanPropertyHandler(pd);
}

将PropertyDescriptor包装为BeanPropertyHandler(其是BeanWrapperImp的内部类):

private class BeanPropertyHandler extends PropertyHandler {
   private final PropertyDescriptor pd;
}
protected abstract static class PropertyHandler(定义在AbstractNestablePropertyAccessor中) {
   private final Class<?> propertyType;
   private final boolean readable;
   private final boolean writable;
}

现在有了BeanPropertyHandler我们再回到前面的getPropertyValue方法:  

protected Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
   String propertyName = tokens.canonicalName;
   String actualName = tokens.actualName;
   PropertyHandler ph = getLocalPropertyHandler(actualName);
   if (ph == null || !ph.isReadable()) {
      throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);
   }
          ..........
      Object value = ph.getValue();
      ...........
      return value;
}

现在是ph.getValue:

public Object getValue() throws Exception {
   final Method readMethod = this.pd.getReadMethod();
      ............
      ReflectionUtils.makeAccessible(readMethod);
      return readMethod.invoke(getWrappedInstance(), (Object[]) null);
   }
}
public final Object getWrappedInstance() {
   Assert.state(this.wrappedObject != null, "No wrapped object");
   return this.wrappedObject;
}

通过反射执行对应的read方法,获取返回值,拿到返回值后再运行newNestedPropertyAccessor方法:

private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
    .............
   PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
   String canonicalName = tokens.canonicalName;
   Object value = getPropertyValue(tokens);
         ..........
      nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR);
     ..........
   return nestedPa;
}

这个newNestedPropertyAccessor也是一个抽象方法,其在BeanWrapperImp的实现是:

protected BeanWrapperImpl newNestedPropertyAccessor(Object object, String nestedPath) {
   return new BeanWrapperImpl(object, nestedPath, this);
}

可以看到这里是将返回的对象再包为一个BeanWrapperImpl对象。

我们再回到前面AbstractNestablePropertyAccessor类:

protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
   int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
   // Handle nested properties recursively.
   if (pos > -1) {
      String nestedProperty = propertyPath.substring(0, pos);
      String nestedPath = propertyPath.substring(pos + 1);
      AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
      return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
   }
   else {
      return this;
   }
}

这里实际是AbstractNestablePropertyAccessor的getPropertyAccessorForPropertyPath循环调用如果不是这个address.city这种一个类型嵌套另一个对象再去获取对应属性。就是直接返回this,例如,如果是获取属性name的value就直接返回是原来的AbstractNestablePropertyAccessor 对象。

    所以这上面的getPropertyAccessorForPropertyPath过程总结就是:

      如果没有进行一个类型A套另一个类型B去获取属性。就返回原来的AbstractNestablePropertyAccessor ,不会再去调getNestedPropertyAccessor方法了如果是一个对象套另一个对象,就通过getNestedPropertyAccessor方法,创建类型B的AbstractNestablePropertyAccessor

    在这里我们可以看到这个wrappedObject已经变为是Address了,而原来有提到通过createAccessor(target)产生的是Persion。

                  

然后我们再回到原来的方法调用:

public Object getPropertyValue(String propertyName) throws BeansException {
   AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName);
   PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
   return nestedPa.getPropertyValue(tokens);
}

 

           

同时这个PropertyTokenHolder也是变为描叙Address的属性city了。

下面就是调用getPropertyValue,去获取对应的值了。这个getPropertyValue在前面已经讲过了,所以整个获取过程就完成了。

   setPropertyValue

@Override
public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
   AbstractNestablePropertyAccessor nestedPa;
   try {
      nestedPa = getPropertyAccessorForPropertyPath(propertyName);
   }
   catch (NotReadablePropertyException ex) {
      throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
            "Nested property in path '" + propertyName + "' does not exist", ex);
   }
   PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
   nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
}

  可以看到这里是与前面getPropertyValue方法一样的,只是最后调用的是setPropertyValue方法:

protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
   if (tokens.keys != null) {
      processKeyedProperty(tokens, pv);
   }
   else {
      processLocalProperty(tokens, pv);
   }
}
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
   PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
   if (ph == null || !ph.isWritable()) {
      ..........
         return;
      }
    ........
   }
   Object oldValue = null;
   try {
      Object originalValue = pv.getValue();
      Object valueToApply = originalValue;
           .......
            if (isExtractOldValueForEditor() && ph.isReadable()) {
                ......
                  oldValue = ph.getValue();
                ..........
            valueToApply = convertForProperty(
      tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
       ...........
      ph.setValue(valueToApply);
   }
}

这个getLocalPropertyHandler方法在前面get方法时也讲了,然后是调用ph.getValue()方法去获取原来的值,在调用convertForProperty方法:

private Object convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue,
      @Nullable Object newValue, @Nullable Class<?> requiredType, @Nullable TypeDescriptor td)
      throws TypeMismatchException {
        ..............
      return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
     ...........
}

这里就是进行类型转换了。

类型转换之后就调用ph.setValue(valueToApply),将其设置到wrappedObject对象中:

   

public void setValue(final @Nullable Object value) throws Exception {
      final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
            ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
            this.pd.getWriteMethod());
         ...............
         ReflectionUtils.makeAccessible(writeMethod);
         writeMethod.invoke(getWrappedInstance(), value);
      }
   }
}

这个getWrappedInstance方法就是获取这个AbstractNestablePropertyAccessor实现类BeanWrapperImp的wrapperObject对象:

return this.wrappedObject;

至此,关于是怎样设置一个Bean对象的属性就梳理完毕。

 

 

 

 

 

 

 

 

 

 

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐