spring--8--BeanWrapper

spring–BeanWrapper

文章目录

1 用途

它最大的作用就是将bean实例和类型转换对象封装到一起,对属性进行类型转换

2 BeanWrapperImpl的继承体系

在这里插入图片描述

典型的接口隔离,一层一层的增加功能。

在这里插入图片描述

总结

  • PropertyEditorRegistry接口很简单,提供注册和查找自定义的PropertyEditor功能,这个接口很重要,如果我们需要向spring中注册自定义的PropertyEditor,就需要借助这个接口。
  • TypeConverter接口定义的4个方法,都是判断是否需要进行类型转换,后面三个方法标识object的来源(方法参数,属性)。
  • PropertyAccessor属性寄存器,提供了访问属性PropertyValue的方法,以及判断属性是否可读可写。
  • ConfigurablePropertyAccessor可配的属性寄存器,接口提供了几个设置ConversionService的方法。
  • BeanWrapper接口就简单了,获取实例,获取实例类型,获取bean的属性描述。BeanWrapper拥有上述所有接口的功能。但是spring为什么要提供这样一个bean的包装呢?其实主要是为了解决两个问题
    • bean实例化之后,需要进行属性填充,此时就需要就行属性访问和设置了。
    • XML中配置bean的属性值均为String类型,而该属性的真实类型却不一定是String,此时需要进行类型转换。

3 spring实例化bean后创建BeanWrapper对象

经过前面几篇文章的学习,我们知道spring在实例化bean之后,就会将bean包装为Beanwrapper类型的对象

下面是spring实例化bean的过程

/**
 * Instantiate the given bean using its default constructor.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @return a BeanWrapper for the new instance
 */
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged(
                (PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
                getAccessControlContext());
        }
        else {
            //策略模式完成bean的实例化
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
        }
        //使用实例化后的对象构建一个BeanWrapper,见3.1
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        //初始化BeanWrapper,见3.2
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

3.1 使用实例化后的对象构建一个BeanWrapper

/**
 * Create a new BeanWrapperImpl for the given object.
 * @param object the object wrapped by this BeanWrapper
 */
public BeanWrapperImpl(Object object) {
   super(object);
}

调用父类构造方法完成对象创建

/**
 * Create a new accessor for the given object.
 * @param object the object wrapped by this accessor
 */
protected AbstractNestablePropertyAccessor(Object object) {
    //允许向BeanWrapper中注册默认的PropertyEditor
    registerDefaultEditors();
    //保存被包装的实例
    setWrappedInstance(object);
}

/**
 * Activate the default editors for this registry instance,
 * allowing for lazily registering default editors when needed.
 * 开启懒加载的方式向BeanWrapper中注册默认的PropertyEditor,用于兜底,
 * 当找不到合适的PropertyEditor用于类型转换,就尝试使用默认的
 */
protected void registerDefaultEditors() {
    this.defaultEditorsActive = true;
}

/**
 * Switch the target object, replacing the cached introspection results only
 * if the class of the new object is different to that of the replaced object.
 * @param object the new target object
 * 保存被包装的实例
 */
public void setWrappedInstance(Object object) {
    //这个方法被子类BeanWrapperImpl重写了
    setWrappedInstance(object, "", null);
}

/**
 * Switch the target object, replacing the cached introspection results only
 * if the class of the new object is different to that of the replaced object.
 * @param object the new target object
 * @param nestedPath the nested path of the object
 * @param rootObject the root object at the top of the path
 * 这个方法又被子类调用了
 */
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 : "");
    /**
     * 这个rootObject是什么,已经有了wrappedObject为什么还需要一个rootObject?
     * 其实这个rootObject主要用来保存嵌套属性的上级实例
     * 举个例子, 对于这种情况<property name="role.rolename" value="wx"></property>
     * 我们只获取到user对象的BeanWrapper肯定不行,因为你根本不可能使用反射跨类调用setRolename
     * 方法来将值设置到user对象中,必须要获得role的BeanWrapper,然后使用反射修改值。
     * 在这种情况下,wrappedObject是role对象,而rootObject就是user对象了
     */
    this.rootObject = (!this.nestedPath.isEmpty() ? rootObject : this.wrappedObject);
    this.nestedPropertyAccessors = null;
    //委托模式,将具体的类型转换逻辑委托给了TypeConverterDelegate
    this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
}

BeanWrapperImpl重写setWrappedInstance方法

@Override
public void setWrappedInstance(Object object, @Nullable String nestedPath, @Nullable Object rootObject) {
    //又调用了父类的setWrappedInstance方法
    super.setWrappedInstance(object, nestedPath, rootObject);
    //重置内省的缓存
    setIntrospectionClass(getWrappedClass());
}

//getClass方法获取实例的clazz对象
public final Class<?> getWrappedClass() {
    return getWrappedInstance().getClass();
}

/**
 * Set the class to introspect.
 * Needs to be called when the target object changes.
 * @param clazz the class to introspect
 */
protected void setIntrospectionClass(Class<?> clazz) {
    //重置内省的缓存
    if (this.cachedIntrospectionResults != null && this.cachedIntrospectionResults.getBeanClass() != clazz) {
        this.cachedIntrospectionResults = null;
    }
}

3.2 初始化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.
 * <p>The default implementation delegates to {@link #registerCustomEditors}.
 * Can be overridden in subclasses.
 * @param bw the BeanWrapper to initialize
 */
protected void initBeanWrapper(BeanWrapper bw) {
    /**
     * getConversionService()方法获取工厂中的ConversionServic对象
     * 将其注册到BeanWrapper中
     */
    bw.setConversionService(getConversionService());
    //将用户自定义的PropertyEditor注册到BeanWrapper中
    registerCustomEditors(bw);
}

将用户自定义的PropertyEditor注册到BeanWrapper

/**
 * Initialize the given PropertyEditorRegistry with the custom editors
 * that have been registered with this BeanFactory.
 * <p>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();
    }
    
    //执行工厂中的所有PropertyEditorRegistrar的registerCustomEditors方法批量注册用户自定义的PropertyEditor
    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;
            }
        }
    }
    //实例化并注册用户自定义的PropertyEditor
    if (!this.customEditors.isEmpty()) {
        this.customEditors.forEach((requiredType, editorClass) ->
                                   registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
    }
}

结合我们在配置文件中配置的CustomEditorConfigurer,它是一个BeanFactoryPostProcessor,所以我们直接看postProcessBeanFactory方法

@Nullable
private PropertyEditorRegistrar[] propertyEditorRegistrars;

@Nullable
private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    if (this.propertyEditorRegistrars != null) {
        for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
            //注册到工厂中
            beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
        }
    }
    if (this.customEditors != null) {
        //注册到工厂中
        this.customEditors.forEach(beanFactory::registerCustomEditor);
    }
}

也就是说,只要我们将自定义的PropertyEditorRegistrar或者PropertyEditor放到CustomEditorConfigurer中,spring就会自动的使用它们。

4 AbstractNestablePropertyAccessor

该类是BeanWrapperImpl的父类,之所以在这里开一个章节讲解它的父类,主要是因为下面的方法大量用到这个类,不讲解清楚就看不懂流程。

首先来看它的属性

public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyAccessor {

    private int autoGrowCollectionLimit = Integer.MAX_VALUE;

    //被包装的bean对象
    @Nullable
    Object wrappedObject;

    //嵌套路径
    private String nestedPath = "";

    //根对象
    @Nullable
    Object rootObject;

    /** 
     * 缓存的嵌套属性寄存器实例
     * nested path -> Accessor instance
     */
    @Nullable
    private Map<String, AbstractNestablePropertyAccessor> nestedPropertyAccessors;
}

4.1 PropertyHandler

该类是AbstractNestablePropertyAccessor的抽象嵌套类

/**
 * A handler for a specific property.
 */
protected abstract static class PropertyHandler {

    //属性类型
   private final Class<?> propertyType;

    //是否可读
   private final boolean readable;

    //是否可写
   private final boolean writable;

   public PropertyHandler(Class<?> propertyType, boolean readable, boolean writable) {
      this.propertyType = propertyType;
      this.readable = readable;
      this.writable = writable;
   }

   public Class<?> getPropertyType() {
      return this.propertyType;
   }

   public boolean isReadable() {
      return this.readable;
   }

   public boolean isWritable() {
      return this.writable;
   }

   public abstract TypeDescriptor toTypeDescriptor();

   public abstract ResolvableType getResolvableType();

   @Nullable
   public Class<?> getMapKeyType(int nestingLevel) {
      return getResolvableType().getNested(nestingLevel).asMap().resolveGeneric(0);
   }

   @Nullable
   public Class<?> getMapValueType(int nestingLevel) {
      return getResolvableType().getNested(nestingLevel).asMap().resolveGeneric(1);
   }

   @Nullable
   public Class<?> getCollectionType(int nestingLevel) {
      return getResolvableType().getNested(nestingLevel).asCollection().resolveGeneric();
   }

   @Nullable
   public abstract TypeDescriptor nested(int level);

   @Nullable
   public abstract Object getValue() throws Exception;

   public abstract void setValue(@Nullable Object value) throws Exception;
}

而它对应的实现定义在BeanWrapperImpl类中,不过此时它是一个内部类

private class BeanPropertyHandler extends PropertyHandler {

    //属性描述
    private final PropertyDescriptor pd;

    //PropertyDescriptor中保存了属性所有信息,快速初始化一个属性处理器
    public BeanPropertyHandler(PropertyDescriptor pd) {
        super(pd.getPropertyType(), pd.getReadMethod() != null, pd.getWriteMethod() != null);
        this.pd = pd;
    }

    @Override
    public ResolvableType getResolvableType() {
        //解析getter方法的返回值
        return ResolvableType.forMethodReturnType(this.pd.getReadMethod());
    }

    /**
     * 获取当前属性的类型描述
     * 具体的过程见10.3和10.4
     */
    @Override
    public TypeDescriptor toTypeDescriptor() {
        return new TypeDescriptor(property(this.pd));
    }

    //嵌套属性的类型描述
    @Override
    @Nullable
    public TypeDescriptor nested(int level) {
        return TypeDescriptor.nested(property(this.pd), level);
    }

    /**
     * 获取属性值
     * 实际上就是通过反射调用getter方法得到属性值
     */
    @Override
    @Nullable
    public Object getValue() throws Exception {
        Method readMethod = this.pd.getReadMethod();
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                ReflectionUtils.makeAccessible(readMethod);
                return null;
            });
            try {
                return AccessController.doPrivileged((PrivilegedExceptionAction<Object>)
                                                     () -> readMethod.invoke(getWrappedInstance(), (Object[]) null), acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            ReflectionUtils.makeAccessible(readMethod);
            return readMethod.invoke(getWrappedInstance(), (Object[]) null);
        }
    }

    /**
     * 设置属性值
     * 实际上就是通过反射调用setter方法设置属性值
     */
    @Override
    public void setValue(@Nullable Object value) throws Exception {
        Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
                              ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
                              this.pd.getWriteMethod());
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                ReflectionUtils.makeAccessible(writeMethod);
                return null;
            });
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>)
                                              () -> writeMethod.invoke(getWrappedInstance(), value), acc);
            }
            catch (PrivilegedActionException ex) {
                throw ex.getException();
            }
        }
        else {
            ReflectionUtils.makeAccessible(writeMethod);
            writeMethod.invoke(getWrappedInstance(), value);
        }
    }
}

总结:该类封装了属性的所有信息,提供一些字段缓存了我们需要经常访问的计算结果,并提供setValue()方法、getValue()方法设置和获取属性

4.2 PropertyTokenHolder

该类是AbstractNestablePropertyAccessor的嵌套类

/**
 * Holder class used to store property tokens.
 */
protected static class PropertyTokenHolder {

    public PropertyTokenHolder(String name) {
        this.actualName = name;
        this.canonicalName = name;
    }

    //属性的真实名字
    public String actualName;

    //规范名称名
    public String canonicalName;

    //[]中的内容
    @Nullable
    public String[] keys;
}

简单封装属性名

5 PropertyDescriptor

属性描述

6 BeanWrapperImpl

public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper {

    /**
     * 内省工具类,提供了很多支持内省的方法
     * 并缓存内省结果 
     */
    @Nullable
    private CachedIntrospectionResults cachedIntrospectionResults;

    /**
     * 安全上下文
     */
    @Nullable
    private AccessControlContext acc;
}

BeanWrapperImpl类还是比较简单的,它仅仅在父类的基础上提供内省支持

6.1 构造方法

/**
 * Create a new BeanWrapperImpl for the given object,
 * registering a nested path that the object is in.
 * @param object the object wrapped by this BeanWrapper
 * @param nestedPath the nested path of the object
 * @param parent the containing BeanWrapper (must not be {@code null})
 */
private BeanWrapperImpl(Object object, String nestedPath, BeanWrapperImpl parent) {
   super(object, nestedPath, parent);
   setSecurityContext(parent.acc);
}

父类构造方法完成对象初始化

/**
 * Create a new accessor for the given object,
 * registering a nested path that the object is in.
 * @param object the object wrapped by this accessor
 * @param nestedPath the nested path of the object
 * @param parent the containing accessor (must not be {@code null})
 */
protected AbstractNestablePropertyAccessor(Object object, String nestedPath, AbstractNestablePropertyAccessor parent) {
    //该方法见3.1,核心是保存父对象parent.getWrappedInstance()
    setWrappedInstance(object, nestedPath, parent.getWrappedInstance());
    //下面都是一些字段值的的拷贝
    setExtractOldValueForEditor(parent.isExtractOldValueForEditor());
    setAutoGrowNestedPaths(parent.isAutoGrowNestedPaths());
    setAutoGrowCollectionLimit(parent.getAutoGrowCollectionLimit());
    setConversionService(parent.getConversionService());
}

这个构造方法你就关心一下setWrappedInstance()方法即可

7 isWritableProperty(String propertyName)方法,判断属性是否可写

public boolean isWritableProperty(String propertyName) {
    try {
        //获取指定属性名的PropertyHandler属性处理器,见8
        PropertyHandler ph = getPropertyHandler(propertyName);
        //判断该属性是否可写(setter方法)
        if (ph != null) {
            return ph.isWritable();
        }
        else {
            // Maybe an indexed/mapped property...
            getPropertyValue(propertyName);
            return true;
        }
    }
    /**
     * 此处的异常捕获很重要,当我们propertyName是嵌套属性名,且外层属性没有初始值的时候
     * 获取propertyName对应的PropertyHandler属性处理器就会抛异常,由此处捕获,返回false
     * 表明该嵌套属性不可写,然后该属性就不会现在进行类型转换,而是等到属性填充的时候(也就是第9章节
     * 的方法)再进行类型转换
     */
    catch (InvalidPropertyException ex) {
        // Cannot be evaluated, so can't be writable.
    }
    return false;
}

8 getPropertyHandler(String propertyName)方法,获取指定属性名的PropertyHandler

/**
 * Return the {@link PropertyHandler} for the specified {@code propertyName}, navigating
 * if necessary. Return {@code null} if not found rather than throwing an exception.
 * @param propertyName the property to obtain the descriptor for
 * @return the property descriptor for the specified property,
 * or {@code null} if not found
 * @throws BeansException in case of introspection failure
 */
@Nullable
protected PropertyHandler getPropertyHandler(String propertyName) throws BeansException {
    Assert.notNull(propertyName, "Property name must not be null");
    //递归检查并获取属性的PropertyAccessor对象,见8.1
    AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName);
    /**
     * getFinalPath()方法,获取最后一个属性名,例如role.rolename,那么调用该方法后就是rolename,见8.2
     * getLocalPropertyHandler()方法,获取属性处理器,见8.3
     */
    return nestedPa.getLocalPropertyHandler(getFinalPath(nestedPa, propertyName));
}

8.1 递归检查并获取属性的PropertyAccessor对象

主要是考虑到这种情况

<bean id="user" class="com.lx.converter.domain.User">
    <!--这两个不能调换顺序,否则会报错-->
    <property name="role" ref="role"></property>
    <!--可以覆盖role中的默认值-->
    <property name="role.rolename" value="role"></property>
</bean>

<bean id="role" class="com.lx.converter.domain.Role">
    <property name="rolename" value="lx"></property>
</bean>

role.rolename的进行特殊处理

/**
 * Recursively navigate to return a property accessor for the nested property path.
 * @param propertyPath property path, which may be nested
 * @return a property accessor for the target bean
 */
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
    //获取第一个属性分隔符的索引(分隔符为.)
    int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
    // Handle nested properties recursively.
    //嵌套属性,进行递归
    if (pos > -1) {
        //外层的属性role
        String nestedProperty = propertyPath.substring(0, pos);
        //内层的rolename
        String nestedPath = propertyPath.substring(pos + 1);
        //获取role的属性寄存器
        AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
        //递归,判断rolename中是否还有嵌套,获取到最终属性的PropertyAccessor
        return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
    }
     //非嵌套属性,直接使用当前bean属性寄存器,即当前BeanWrapperImpl对象
    else {
        return this;
    }
}

我们来看一下role属性的属性寄存器是如何获取的?

/**
 * Retrieve a Property accessor for the given nested property.
 * Create a new one if not found in the cache.
 * <p>Note: Caching nested PropertyAccessors is necessary now,
 * to keep registered custom editors for nested properties.
 * @param nestedProperty property to create the PropertyAccessor for
 * @return the PropertyAccessor instance, either cached or newly created
 */
private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
    //缓存的嵌套属性寄存器,见4
    if (this.nestedPropertyAccessors == null) {
        this.nestedPropertyAccessors = new HashMap<>();
    }
    // Get value of bean property.
    /**
     * 这里解析属性名,获取规范名,见8.1.1
     * 还是role,然后新旧名字封装成PropertyTokenHolder
     */
    PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
    //规范名
    String canonicalName = tokens.canonicalName;
    /**
     * 获取bean对象中指定属性对应的值,见8.1.2
     * 获取role属性对象,通过getter方法得到
     * 初次访问value肯定是null,因为我们并没有给role属性设置值
     */
    Object value = getPropertyValue(tokens);
    /**
     * role属性为null,但是你却想给role内部的rolename赋值,那肯定抛异常
     */
    if (value == null || (value instanceof Optional && !((Optional<?>) value).isPresent())) {
        if (isAutoGrowNestedPaths()) {
            value = setDefaultValue(tokens);
        }
        //抛异常,跳过后面的代码
        else {
            throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName);
        }
    }

    /*****************************************************************************/

    // Lookup cached sub-PropertyAccessor, create new one if not found.
    /**
     * 到了这一步就说明嵌套属性的外部属性有值,即对于role.rolename来说,role属性有值
     * 值从哪儿来的,有两种情况
     * 1.private Role role=new Role(),role有默认值(Field)
     * 2.调用getRole()方法的返回不为null(Property)
     * 3.role属性已经进行属性填充了,现在填充role.rolename了,所以此时能够获取到role对象(对应9
     * 章节中调用该方法)
     *
     * 8章节对应的方法会在两个地方法被调用,第一个是7中的isWritableProperty()方法中调用一次,
     * 此时若是嵌套属性,通过getter方法访问外部属性得到null,那么此时嵌套属性就不可写,不会马上进行
     * 类型转换,而是等到9章节方法调用时再尝试一次
     */
    //再次从缓存中获取一次嵌套属性的属性寄存器
    AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName);
    if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'");
        }
        //将外部属性对象包装为BeanWrapperImpl对象
        nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR);
        // Inherit all type-specific PropertyEditors.
        //拷贝PropertyEditor到刚创建的BeanWrapperImpl对象中
        copyDefaultEditorsTo(nestedPa);
        copyCustomEditorsTo(nestedPa, canonicalName);
        //缓存嵌套属性的PropertyAccessor
        this.nestedPropertyAccessors.put(canonicalName, nestedPa);
    }
    else {
        if (logger.isTraceEnabled()) {
            logger.trace("Using cached nested property accessor for property '" + canonicalName + "'");
        }
    }
    return nestedPa;
}


/**
 * 创建外部属性对象的BeanWrapperImpl对象
 * 保存了父BeanWrapperImpl对象,见6.1
 */
protected BeanWrapperImpl newNestedPropertyAccessor(Object object, String nestedPath) {
    return new BeanWrapperImpl(object, nestedPath, this);
}

对于嵌套属性,getNestedPropertyAccessor(String nestedProperty)方法会进来2

  • 第一次进来,是在isWritableProperty(String propertyName)方法中,它尝试获取外部属性值,发现外部属性默认值为null,于是方法就抛出异常,被isWritableProperty(String propertyName)方法捕获到异常,直接返回false,表明当前属性不可写,跳过初次类型转换
  • 第二次进来,是在setPropertyValues(PropertyValues pvs)方法中,该方法中开始按照顺序对每一个属性进行填充,发现有属性(也就是嵌套属性)还没有进行类型转换,于是就先取出外部属性值,包装为BeanWrapperImpl对象,然后进行类型转换,再通过这个BeanWrapperImpl对象的getLocalPropertyHandler()方法得到对应属性的属性处理器PropertyHandler,最后调用属性处理器的setValue()方法填充属性
  • BeanWrapperImpl就是属性寄存器

8.1.1 将属性名解析为相应的属性名称标记

/**
 * Parse the given property name into the corresponding property name tokens.
 * @param propertyName the property name to parse
 * @return representation of the parsed property tokens
 */
private PropertyTokenHolder getPropertyNameTokens(String propertyName) {
    String actualName = null;
    List<String> keys = new ArrayList<>(2);
    int searchIndex = 0;
    while (searchIndex != -1) {
        /**
         * PROPERTY_KEY_PREFIX=[
         * 从索引位置searchIndex开始获得propertyName中[的索引
         */
        int keyStart = propertyName.indexOf(PROPERTY_KEY_PREFIX, searchIndex);
        searchIndex = -1;
        //属性名中有[
        if (keyStart != -1) {
            //找到与这个[对应的]索引位置
            int keyEnd = getPropertyNameKeyEnd(propertyName, keyStart + PROPERTY_KEY_PREFIX.length());
            //找到了
            if (keyEnd != -1) {
                /**
                 * 只有第一次才会给actualName赋值
                 * 也就是说,propertyName中第一个[符号左边的字符串就是该属性的真实名
                 */
                if (actualName == null) {
                    /**
                     * 真实的属性名
                     * 这里截取的是[之前的部分
                     */
                    actualName = propertyName.substring(0, keyStart);
                }
                //得到[]符号中的内容
                String key = propertyName.substring(keyStart + PROPERTY_KEY_PREFIX.length(), keyEnd);
                /**
                 * []中的内容有3种写法
                 * 1.什么都不加
                 * 2.'内容'
                 * 3.\内容
                 */
                if (key.length() > 1 && (key.startsWith("'") && key.endsWith("'")) ||
                    (key.startsWith("\"") && key.endsWith("\""))) {
                    key = key.substring(1, key.length() - 1);
                }
                //保存到keys集合中
                keys.add(key);
                /** 
                 * PROPERTY_KEY_SUFFIX=]
                 * 接着去解析下一个[]符号内容
                 * 主要是为了解决wx[xx].de[xx]
                 */
                searchIndex = keyEnd + PROPERTY_KEY_SUFFIX.length();
            }
        }
    }

    /**
     * 使用真实属性名创建一个属性名称标记对象,见4.2
     */
    PropertyTokenHolder tokens = new PropertyTokenHolder(actualName != null ? actualName : propertyName);
    //属性名中有[]
    if (!keys.isEmpty()) {
        /**
         * 属性名中有[]的属性的规范名称
         * collectionToDelimitedString()方法,将keys集合转[]符号分割的字符串
         */
        tokens.canonicalName += PROPERTY_KEY_PREFIX +
            StringUtils.collectionToDelimitedString(keys, PROPERTY_KEY_SUFFIX + PROPERTY_KEY_PREFIX) +
            PROPERTY_KEY_SUFFIX;
        //集合转数组,并保存到规范名称标记对象中
        tokens.keys = StringUtils.toStringArray(keys);
    }
    return tokens;
}


/**
 * 找到与[匹配的]
 * 可能存在[df[dg]]这种情况
 */
private int getPropertyNameKeyEnd(String propertyName, int startIndex) {
    int unclosedPrefixes = 0;
    int length = propertyName.length();
    for (int i = startIndex; i < length; i++) {
        switch (propertyName.charAt(i)) {
                //[
            case PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR:
                // The property name contains opening prefix(es)...
                unclosedPrefixes++;
                break;
                //]
            case PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR:
                if (unclosedPrefixes == 0) {
                    // No unclosed prefix(es) in the property name (left) ->
                    // this is the suffix we are looking for.
                    return i;
                }
                else {
                    // This suffix does not close the initial prefix but rather
                    // just one that occurred within the property name.
                    unclosedPrefixes--;
                }
                break;
        }
    }
    return -1;
}

总结:

  • 如果属性名中不包含[]符号,那么属性真实名actualName直接就是原始名,不用处理
  • 如果属性名中包含[]符号,那么就需要做如下处理
    • 首先获取原始属性名中第一个[符号左边的内容作为属性真实名actualName
    • 随后一个一个的解析[]符号,得到里面的内容,保存到keys集合中。这里只会解析并行的wx[xx].de[lx],不会解析[df[dg]],也就是说第一个能解析到xxlx,第二个只能直接到df[dg],毕竟第二种写法不对。
    • 最后就开始拼接了,得到规范名称,按tokens.canonicalName += PROPERTY_KEY_PREFIX +StringUtils.collectionToDelimitedString(keys, PROPERTY_KEY_SUFFIX + PROPERTY_KEY_PREFIX) +PROPERTY_KEY_SUFFIX;规则

8.1.2 获取bean对象中指定属性对应的值

protected Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
    //规范名
    String propertyName = tokens.canonicalName;
    //真实名
    String actualName = tokens.actualName;
    /**
     * 获取指定属性名的PropertyHandler属性处理器,见8.3
     * 就是通过内省访问User,然后获取role属性的PropertyHandler
     */
    PropertyHandler ph = getLocalPropertyHandler(actualName);
    //isReadable()判断属性有没有对应的getter方法
    if (ph == null || !ph.isReadable()) {
        throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);
    }
    try {
        /**
         * 反射调用属性的getter方法得到属性值,见4.1
         * 实际上就是调用role属性的getter方法,获取role对象
         * 获取到这个role对象就可以修改它的属性值了
         */
        Object value = ph.getValue();

        /*******************************处理keys********************************/
        //这里面的keys我也没弄懂,先放一下
        if (tokens.keys != null) {
            if (value == null) {
                if (isAutoGrowNestedPaths()) {
                    value = setDefaultValue(new PropertyTokenHolder(tokens.actualName));
                }
                else {
                    throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
                                                             "Cannot access indexed value of property referenced in indexed " +
                                                             "property path '" + propertyName + "': returned null");
                }
            }
            StringBuilder indexedPropertyName = new StringBuilder(tokens.actualName);
            // apply indexes and map keys
            for (int i = 0; i < tokens.keys.length; i++) {
                String key = tokens.keys[i];
                if (value == null) {
                    throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
                                                             "Cannot access indexed value of property referenced in indexed " +
                                                             "property path '" + propertyName + "': returned null");
                }
                else if (value.getClass().isArray()) {
                    int index = Integer.parseInt(key);
                    value = growArrayIfNecessary(value, index, indexedPropertyName.toString());
                    value = Array.get(value, index);
                }
                else if (value instanceof List) {
                    int index = Integer.parseInt(key);
                    List<Object> list = (List<Object>) value;
                    growCollectionIfNecessary(list, index, indexedPropertyName.toString(), ph, i + 1);
                    value = list.get(index);
                }
                else if (value instanceof Set) {
                    // Apply index to Iterator in case of a Set.
                    Set<Object> set = (Set<Object>) value;
                    int index = Integer.parseInt(key);
                    if (index < 0 || index >= set.size()) {
                        throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
                                                           "Cannot get element with index " + index + " from Set of size " +
                                                           set.size() + ", accessed using property path '" + propertyName + "'");
                    }
                    Iterator<Object> it = set.iterator();
                    for (int j = 0; it.hasNext(); j++) {
                        Object elem = it.next();
                        if (j == index) {
                            value = elem;
                            break;
                        }
                    }
                }
                else if (value instanceof Map) {
                    Map<Object, Object> map = (Map<Object, Object>) value;
                    Class<?> mapKeyType = ph.getResolvableType().getNested(i + 1).asMap().resolveGeneric(0);
                    // IMPORTANT: Do not pass full property name in here - property editors
                    // must not kick in for map keys but rather only for map values.
                    TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
                    Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
                    value = map.get(convertedMapKey);
                }
                else {
                    throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
                                                       "Property referenced in indexed property path '" + propertyName +
                                                       "' is neither an array nor a List nor a Set nor a Map; returned value was [" + value + "]");
                }
                indexedPropertyName.append(PROPERTY_KEY_PREFIX).append(key).append(PROPERTY_KEY_SUFFIX);
            }
        }
        /********************************************************************/

        //直接返回getter方法的调用结果,即属性对应值
        return value;
    }
    catch (IndexOutOfBoundsException ex) {
        throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
                                           "Index of out of bounds in property path '" + propertyName + "'", ex);
    }
    catch (NumberFormatException | TypeMismatchException ex) {
        throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
                                           "Invalid index in property path '" + propertyName + "'", ex);
    }
    catch (InvocationTargetException ex) {
        throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
                                           "Getter for property '" + actualName + "' threw exception", ex);
    }
    catch (Exception ex) {
        throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
                                           "Illegal attempt to get property '" + actualName + "' threw exception", ex);
    }
}

总结:

  1. 调用getLocalPropertyHandler(actualName)方法得到真实属性名actualNamePropertyHandler属性处理器
  2. 判断属性有没有getter方法,没有抛异常
  3. 调用属性处理器的ph.getValue()方法得到属性默认值

8.2 获取属性中最后一部分(针对嵌套属性)

/**
 * Get the last component of the path. Also works if not nested.
 * @param pa property accessor to work on
 * @param nestedPath property path we know is nested
 * @return last component of the path (the property on the target bean)
 */
protected String getFinalPath(AbstractNestablePropertyAccessor pa, String nestedPath) {
    /**
     * 属性寄存器是当前的BeanWrapperImpl对象
     * 说明当前属性不是嵌套属性,见8.1
     * 那就直接使用当前属性路径
     */
    if (pa == this) {
        return nestedPath;
    }
    //否则截取属性,得到属性最后一部分
    return nestedPath.substring(PropertyAccessorUtils.getLastNestedPropertySeparatorIndex(nestedPath) + 1);
}
  • 非嵌套属性不做处理
  • 嵌套属性则截取得到最后一个.后面部分

8.3 获取指定属性名的PropertyHandler属性处理器

protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
    //获取属性名对应的PropertyDescriptor,见10.2.3
    PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
    //创建一个BeanPropertyHandler属性处理器,见4.1
    return (pd != null ? new BeanPropertyHandler(pd) : null);
}

/**
 * Obtain a lazily initialized CachedIntrospectionResults instance
 * for the wrapped object.
 */
private CachedIntrospectionResults getCachedIntrospectionResults() {
    if (this.cachedIntrospectionResults == null) {
        //内省,获取javabean对象属性信息,见10.2.2
        this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass());
    }
    return this.cachedIntrospectionResults;
}

总结:

通过spring封装的内省工具类cachedIntrospectionResults的静态方法forClass(beanClass),得到所有属性描述PropertyDescriptor,然后获取指定属性的属性描述,封装为属性处理器BeanPropertyHandler

9 setPropertyValues(PropertyValues pvs)方法,填充经过初步处理的属性(可能还没有进行类型转换)

public void setPropertyValues(PropertyValues pvs) throws BeansException {
    //调用重载的方法进行属性填充
    setPropertyValues(pvs, false, false);
}


@Override
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()));

    if (ignoreUnknown) {
        this.suppressNotWritablePropertyException = true;
    }
    try {
        //遍历,顺序填充属性
        for (PropertyValue pv : propertyValues) {
            // setPropertyValue may throw any BeansException, which won't be caught
            // here, if there is a critical failure such as no matching field.
            // We can attempt to deal only with less serious exceptions.
            try {
                //调用重载的方法进行属性填充
                setPropertyValue(pv);
            }
            catch (NotWritablePropertyException ex) {
                if (!ignoreUnknown) {
                    throw ex;
                }
                // Otherwise, just ignore it and continue...
            }
            catch (NullValueInNestedPathException ex) {
                if (!ignoreInvalid) {
                    throw ex;
                }
                // Otherwise, just ignore it and continue...
            }
            catch (PropertyAccessException ex) {
                if (propertyAccessExceptions == null) {
                    propertyAccessExceptions = new ArrayList<>();
                }
                propertyAccessExceptions.add(ex);
            }
        }
    }
    finally {
        if (ignoreUnknown) {
            this.suppressNotWritablePropertyException = false;
        }
    }

    // If we encountered individual exceptions, throw the composite exception.
    //异常处理
    if (propertyAccessExceptions != null) {
        PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
        throw new PropertyBatchUpdateException(paeArray);
    }
}

这里出现了三个重载的setPropertyValue()方法,一步一步的细化职责,下面这个setPropertyValue方法是针对单个属性进行填充的

@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
    /**
     * 嵌套属性会进入8.1.1,解析得到了PropertyTokenHolder对象,但是它并没有缓存
     * 从下面的流程我们也能知道,只有非嵌套属性才会缓存PropertyTokenHolder对象
     * 并且缓存之后它就进行属性填充了
     * 所以只有非嵌套属性填充过一次之后它的tokens才不为空
     * 主要为了解决覆盖问题
     *  <property name="name" value="lx"></property>
     *  <property name="name" value="wx"></property>
     * 此种情况就不用每次解析属性名了
     */
    PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
    //一般都为null,进入此分支
    if (tokens == null) {
        //获取属性名
        String propertyName = pv.getName();
        AbstractNestablePropertyAccessor nestedPa;
        try {
            /**
             * 获取属性名对应的属性寄存器,方法详情见8
             *
             * 如果是嵌套属性,在此处就能获取到它外部属性的属性寄存器了
             * 这个方法里面会调用外部属性的getter方法得到外部属性对象,再封装为BeanWrapperImpl对象
             * 也就是属性寄存器,这就是为什么要求getRole()方法在role.rolename赋值前必须有值的原因
             */
            nestedPa = getPropertyAccessorForPropertyPath(propertyName);
        }
        catch (NotReadablePropertyException ex) {
            throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
                                                   "Nested property in path '" + propertyName + "' does not exist", ex);
        }
        /**
         * getFinalPath(nestedPa, propertyName) 获取属性名最后一部分,见8.2
         * 比如role.rolename对应的属性名字就是rolename
         * getPropertyNameTokens()实际上就是载对rolename做进一步解析,里面可能有[]之类的符号
         * 新旧名字封装形成PropertyTokenHolder,见8.1.1
         */
        tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
        //非嵌套属性缓存属性名称标记
        if (nestedPa == this) {
            /**
             * 缓存属性名称标记
             * pv.getOriginalPropertyValue()获取用来原始的PropertyValue对象
             * 当我们要填充的属性是一个嵌套属性,且第一次判断它不可写的时候(即7章节),就跳过了类型转换
             * 重新构建了一个PropertyValue对象,并将经过BeanDefinitionValueResolver解析的
             * 属性值设为value字段值,然后调用setSource()方法保存保存原始的PropertyValue对象
             * 如果不存在就返回this,也就是当前的PropertyValue
             */
            pv.getOriginalPropertyValue().resolvedTokens = tokens;
        }
        //填充属性
        nestedPa.setPropertyValue(tokens, pv);
    }

    //只有非嵌套属性且二次填充时才会进入该分支
    else {
        //填充属性
        setPropertyValue(tokens, pv);
    }
}

总结:

  • 一般流程:首先得到它的属性寄存器,然后解析属性名称标记并缓存,最后调用setPropertyValue(tokens, pv)方法完成属性填充
  • 特殊情况:非嵌套属性且二次填充时,直接调用setPropertyValue(tokens, pv)方法完成属性填充

最终发现,无论是嵌套属性还是非嵌套属性,最终都是调用setPropertyValue(tokens, pv)方法实现属性填充

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,见8
    PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
    //当前属性没有setter方法,那肯定不能进行属性填充了,抛异常
    if (ph == null || !ph.isWritable()) {
        if (pv.isOptional()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Ignoring optional value for property '" + tokens.actualName +
                             "' - property not found on bean class [" + getRootClass().getName() + "]");
            }
            return;
        }
        if (this.suppressNotWritablePropertyException) {
            // Optimization for common ignoreUnknown=true scenario since the
            // exception would be caught and swallowed higher up anyway...
            return;
        }
        throw createNotWritablePropertyException(tokens.canonicalName);
    }

    Object oldValue = null;
    try {
        //获取原始值
        Object originalValue = pv.getValue();
        Object valueToApply = originalValue;
        //需要进行类型转换,pv.conversionNecessary默认为null
        if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
            //已经类型转换了
            if (pv.isConverted()) {
                //直接获取类型转换后的值
                valueToApply = pv.getConvertedValue();
            }
            /**
             * 没有类型转换
             * 走到这一步一般是嵌套属性(role.rolename),在嵌套属性的上级对象(role)没有赋值之前
             * ,你获取不到role对象的BeanWrapperImpl对象,也就不能进行类型转换了。
             */
            else {
                /**
                 * isExtractOldValueForEditor()判断是否需要提取旧值进行类型转换
                 * 就是判断extractOldValueForEditor字段值,默认为false
                 * ph.isReadable()判断属性有没有getter方法
                 */
                if (isExtractOldValueForEditor() && ph.isReadable()) {
                    try {
                        //调用属性的getter方法获取属性默认值
                        oldValue = ph.getValue();
                    }
                    catch (Exception ex) {
                        if (ex instanceof PrivilegedActionException) {
                            ex = ((PrivilegedActionException) ex).getException();
                        }
                        if (logger.isDebugEnabled()) {
                            logger.debug("Could not read previous value of property '" +
                                         this.nestedPath + tokens.canonicalName + "'", ex);
                        }
                    }
                }
                /**
                 * 
                 * ph.toTypeDescriptor() 得到当前属性的类型描述,见4.1
                 * convertForProperty()方法,类型转换的核心方法,上篇文章讲过这个方法的源码
                 */
                valueToApply = convertForProperty(
                    tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
            }
            
            //设置是否需要进行需要类型转换的标记,方便下次快速创建对象
            pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
        }
        //反射调用setter方法填充属性,见4.1
        ph.setValue(valueToApply);
    }
    catch (TypeMismatchException ex) {
        throw ex;
    }
    catch (InvocationTargetException ex) {
        PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
            getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
        if (ex.getTargetException() instanceof ClassCastException) {
            throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
        }
        else {
            Throwable cause = ex.getTargetException();
            if (cause instanceof UndeclaredThrowableException) {
                // May happen e.g. with Groovy-generated methods
                cause = cause.getCause();
            }
            throw new MethodInvocationException(propertyChangeEvent, cause);
        }
    }
    catch (Exception ex) {
        PropertyChangeEvent pce = new PropertyChangeEvent(
            getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
        throw new MethodInvocationException(pce, ex);
    }
}

总结一下该方法的大致流程:

  1. 遍历MutablePropertyValues,按顺序填充每一个PropertyValue属性
  2. 解析填充属性的属性名,得到PropertyTokenHolder属性名称标记(里面有真实属性名和规范属性名)
  3. 调用getLocalPropertyHandler(tokens.actualName)方法得到属性的属性处理器PropertyHandler
  4. 验证属性是否包含setter方法,没有就抛异常
  5. 判断PropertyValue属性是否有必要进行类型转换,没有必要就直接通过PropertyHandler属性处理器ph.setValue(valueToApply)方法完成属性赋值,否则就进入6
  6. 判断PropertyValue属性是否已经经过类型转换,未经过类型转换就先类型转换,然后填充属性值,否则直接填充属性值

10 spring使用内省

内省是java提供的一种快捷访问javaBean这种类型类的方式,本质上还是反射。通过内省,可以快速获得getter,setter方法和它们对应的属性。通过内省获取某个类的属性必然包含class属性,因为任何类的对象都有getClass方法。

10.1 FieldProperty的区别

  • Property是相对于gettersetter方法来说的,一个gettersetter方法就代表了一个Property。例如:我们可以通过user.getClass()方法得到user对象的clazz对象,那么User类和它的父类中真的定义了Class class=User.class吗?肯定没有啊,但是我们却可以通过getClass()方法得到clazz对象,也就是说并没有为User类分配了栈内存存储clazz对象的引用。
  • Field则是JDK反射定义的,用来代表类中分配了栈内存的字段,即明确在类中声明了Role role;,这种就是Field

10.2 CachedIntrospectionResults

spring封装了自己的内省工具类CachedIntrospectionResults,也代表一个内省结果

10.2.1 CachedIntrospectionResults的属性

public final class CachedIntrospectionResults {


    public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";

    //空的属性描述数组,如果某个类没有getter、setter方法,就会使用它
    private static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = {};


    //得到根路径下spring.properties文件中spring.beaninfo.ignore的值
    private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
        SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);

    /**
     * 通过某种算法逻辑得到所有的BeanInfoFactory对象
     */
    private static final List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
        BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());


    //可使用的类加载器
    static final Set<ClassLoader> acceptedClassLoaders =
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    //内省结果缓存
    static final ConcurrentMap<Class<?>, CachedIntrospectionResults> strongClassCache =
        new ConcurrentHashMap<>(64);

    //包含类内省结果缓存
    static final ConcurrentMap<Class<?>, CachedIntrospectionResults> softClassCache =
        new ConcurrentReferenceHashMap<>(64);


    //内省结果得到的bean信息
    private final BeanInfo beanInfo;

    /**
     * 某个类的所有属性描述
     * 内省就是为了得到它
     */
    private final Map<String, PropertyDescriptor> propertyDescriptors;

    //属性描述对应的类型描述
    private final ConcurrentMap<PropertyDescriptor, TypeDescriptor> typeDescriptorCache;


}

10.2.2 forClass(Class<?> beanClass)方法, 得到beanClass类的内省结果

/**
 * Create CachedIntrospectionResults for the given bean class.
 * @param beanClass the bean class to analyze
 * @return the corresponding CachedIntrospectionResults
 * @throws BeansException in case of introspection failure
 */
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
    //先从缓存中获取
    CachedIntrospectionResults results = strongClassCache.get(beanClass);
    if (results != null) {
        return results;
    }
    results = softClassCache.get(beanClass);
    if (results != null) {
        return results;
    }

    //创建一个beanClass的可缓存的内省结果
    results = new CachedIntrospectionResults(beanClass);
    ConcurrentMap<Class<?>, CachedIntrospectionResults> classCacheToUse;

    //使用当前类加载器加载的是缓存安全的
    if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
        isClassLoaderAccepted(beanClass.getClassLoader())) {
        classCacheToUse = strongClassCache;
    }
    //不安全
    else {
        if (logger.isDebugEnabled()) {
            logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
        }
        classCacheToUse = softClassCache;
    }

    //缓存
    CachedIntrospectionResults existing = classCacheToUse.putIfAbsent(beanClass, results);
    return (existing != null ? existing : results);
}

/*****************************************************************************/

/**
 * Create a new CachedIntrospectionResults instance for the given class.
 * @param beanClass the bean class to analyze
 * @throws BeansException in case of introspection failure
 */
private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
    try {
        if (logger.isTraceEnabled()) {
            logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
        }
        //内省获取BeanInfo
        this.beanInfo = getBeanInfo(beanClass);

        if (logger.isTraceEnabled()) {
            logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
        }
        this.propertyDescriptors = new LinkedHashMap<>();

        // This call is slow so we do it once.
        //获取beanClass中所有PropertyDescriptor(原生或spring增强的)
        PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            if (Class.class == beanClass &&
                ("classLoader".equals(pd.getName()) ||  "protectionDomain".equals(pd.getName()))) {
                // Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
                continue;
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Found bean property '" + pd.getName() + "'" +
                             (pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") +
                             (pd.getPropertyEditorClass() != null ?
                              "; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
            }
            /**
             * 增强PropertyDescriptor
             * GenericTypeAwarePropertyDescriptor是spring定义,继承了PropertyDescriptor
             * 添加了更多的方法,方便获取属性相关的信息
             */
            pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
            //缓存起来
            this.propertyDescriptors.put(pd.getName(), pd);
        }

        // Explicitly check implemented interfaces for setter/getter methods as well,
        // in particular for Java 8 default methods...
        Class<?> currClass = beanClass;
        while (currClass != null && currClass != Object.class) {
            //内省处理接口有默认实现的setter/getter方法
            introspectInterfaces(beanClass, currClass);
            currClass = currClass.getSuperclass();
        }

        this.typeDescriptorCache = new ConcurrentReferenceHashMap<>();
    }
    catch (IntrospectionException ex) {
        throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex);
    }
}


/**
 * Retrieve a {@link BeanInfo} descriptor for the given target class.
 * @param beanClass the target class to introspect
 * @return the resulting {@code BeanInfo} descriptor (never {@code null})
 * @throws IntrospectionException from the underlying {@link Introspector}
 */
private static BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
    /**
     * spring对原生的内省包装了一下
     * 返回的BeanInfo类型是spring自己定义的ExtendedBeanInfo,实现更强大的功能,获取更多的信息
     */
    for (BeanInfoFactory beanInfoFactory : beanInfoFactories) {
        BeanInfo beanInfo = beanInfoFactory.getBeanInfo(beanClass);
        if (beanInfo != null) {
            return beanInfo;
        }
    }

    //原生,使用的JDK中的Introspector工具类实现内省,返回SimpleBeanInfo,里面方法很少
    return (shouldIntrospectorIgnoreBeaninfoClasses ?
            Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
            Introspector.getBeanInfo(beanClass));
}


//内省处理接口有默认实现的setter/getter方法
private void introspectInterfaces(Class<?> beanClass, Class<?> currClass) throws IntrospectionException {
    //遍历当前类的所有接口
    for (Class<?> ifc : currClass.getInterfaces()) {
        /**
         * isJavaLanguageInterface方法判断是否是这几个Serializable、Externalizable、
         * Closeable、AutoCloseable、Cloneable、Comparable接口
         */
        if (!ClassUtils.isJavaLanguageInterface(ifc)) {
            //内省获取接口的PropertyDescriptor
            for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) {
                /**
                 * 从子类的PropertyDescriptor集合中查找
                 * 判断子类是否重写了接口有默认实现的方法
                 */
                PropertyDescriptor existingPd = this.propertyDescriptors.get(pd.getName());
                if (existingPd == null ||
                    (existingPd.getReadMethod() == null && pd.getReadMethod() != null)) {
                    // GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
                    // against a declared read method, so we prefer read method descriptors here.
                    //增强PropertyDescriptor
                    pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
                    //缓存起来
                    this.propertyDescriptors.put(pd.getName(), pd);
                }
            }
            //递归
            introspectInterfaces(ifc, ifc);
        }
    }
}

真正的内省逻辑是在构造方法实现的,但是查看源码,我们发现构造方法是private,也就是说用户不能直接使用new CachedIntrospectionResults(beanClass)的方式得到一个内省结果,而应该使用它提供的forClass(beanClass)方法来得到内省结果。

10.2.3 getPropertyDescriptors()方法,获取对应属性名的属性描述

@Nullable
PropertyDescriptor getPropertyDescriptor(String name) {
    //通过名字得到对应的属性描述
    PropertyDescriptor pd = this.propertyDescriptors.get(name);
    if (pd == null && StringUtils.hasLength(name)) {
        // Same lenient fallback checking as in Property...
        pd = this.propertyDescriptors.get(StringUtils.uncapitalize(name));
        if (pd == null) {
            pd = this.propertyDescriptors.get(StringUtils.capitalize(name));
        }
    }
    return pd;
}

每一个CachedIntrospectionResults对象中都缓存着内省得到的所有属性描述

10.2.4 getTypeDescriptor(PropertyDescriptor pd)方法,获取对应属性的类型描述

@Nullable
TypeDescriptor getTypeDescriptor(PropertyDescriptor pd) {
   return this.typeDescriptorCache.get(pd);
}

内省解析beanClass的时候只会得到所有属性对应的PropertyDescriptor,如果需要TypeDescriptor,首次需要用户自己解析创建TypeDescriptor,然后加入到缓存typeDescriptorCache中,后面使用就可以直接从缓存中拿了

10.2.5 addTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td)方法,缓存对应属性的类型描述

TypeDescriptor addTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td) {
   TypeDescriptor existing = this.typeDescriptorCache.putIfAbsent(pd, td);
   return (existing != null ? existing : td);
}

用户解析创建TypeDescriptor类型描述之后,调用该方法将TypeDescriptor加入到缓存typeDescriptorCache

10.3 Property

Propertyspring定义的,用来描述一个javaBean属性

这个property()方法构造了一个Property对象

private Property property(PropertyDescriptor pd) {
    GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
    //构造一个Property对象
    return new Property(gpd.getBeanClass(), gpd.getReadMethod(), gpd.getWriteMethod(), gpd.getName());
}

随后spring通过Property对象构建一个TypeDescriptor,要进行类型转换必须要得到TypeDescriptor

下面是Property的字段

public final class Property {

    private static Map<Property, Annotation[]> annotationCache = new ConcurrentReferenceHashMap<>();

    //属性clazz对象
    private final Class<?> objectType;

    @Nullable
    private final Method readMethod;

    @Nullable
    private final Method writeMethod;

    //属性名
    private final String name;

    //方法参数
    private final MethodParameter methodParameter;

    //属性拥有的注解
    @Nullable
    private Annotation[] annotations;
}

10.3.1 构造方法

//使用的是这个构造方法创建的Property对象
public Property(
    Class<?> objectType, @Nullable Method readMethod, @Nullable Method writeMethod, @Nullable String name) {

    this.objectType = objectType;
    this.readMethod = readMethod;
    this.writeMethod = writeMethod;
    //解析getter和setter方法参数,见10.3.2
    this.methodParameter = resolveMethodParameter();
    //根据方法名解析属性名,见10.3.3
    this.name = (name != null ? name : resolveName());
}

构造Property的时候会解析出属性的名字和对应gettersetter方法参数

10.3.2 resolveMethodParameter()方法,解析属性gettersetter方法参数

/**
 * 解析getter和setter方法参数
 * 从这个方法内容上看,优先使用setter方法的参数
 * 当setter方法的参数为null或setter方法和getter方法的参数类型有继承关系的时候才用
 * getter方法的参数
 */
private MethodParameter resolveMethodParameter() {
    //获取读方法的方法参数对象
    MethodParameter read = resolveReadMethodParameter();
    //获取写方法的方法参数对象
    MethodParameter write = resolveWriteMethodParameter();

    if (write == null) {
        if (read == null) {
            //读写方法不能都没有参数
            throw new IllegalStateException("Property is neither readable nor writeable");
        }
        //写方法没有参数就返回读方法的参数
        return read;
    }
    if (read != null) {
        Class<?> readType = read.getParameterType();
        Class<?> writeType = write.getParameterType();
        //读写方法参数不相同,并且具有继承关系则返回读方法参数
        if (!writeType.equals(readType) && writeType.isAssignableFrom(readType)) {
            return read;
        }
    }
    return write;
}

/***************************************************************************************/
//读方法参数是返回值
@Nullable
private MethodParameter resolveReadMethodParameter() {
    //实际上就是获取字段readMethod
    if (getReadMethod() == null) {
        return null;
    }
    return new MethodParameter(getReadMethod(), -1).withContainingClass(getObjectType());
}

//写方法参数是第一个参数
@Nullable
private MethodParameter resolveWriteMethodParameter() {
    //实际上就是获取字段writeMethod
    if (getWriteMethod() == null) {
        return null;
    }
    //构建一个方法参数对象
    return new MethodParameter(getWriteMethod(), 0).withContainingClass(getObjectType());
}
  • 读方法参数实际上就是getter方法的返回值
  • 写方法参数实际上就是setter方法的第一个参数
  • 读方法和写方法不能都没有参数
  • 当写方法没有参数的时候,就使用读方法参数,即getter方法的返回值
  • 如果读写方法参数都存在,那么只有写方法参数类型是读方法参数类型的父类时,才使用读方法参数,否则使用写方法参数

10.3.3 resolveName()方法, 根据方法名解析出属性名

private String resolveName() {
    if (this.readMethod != null) {
        int index = this.readMethod.getName().indexOf("get");
        if (index != -1) {
            index += 3;
        }
        else {
            index = this.readMethod.getName().indexOf("is");
            if (index == -1) {
                throw new IllegalArgumentException("Not a getter method");
            }
            index += 2;
        }
        return StringUtils.uncapitalize(this.readMethod.getName().substring(index));
    }
    else if (this.writeMethod != null) {
        int index = this.writeMethod.getName().indexOf("set");
        if (index == -1) {
            throw new IllegalArgumentException("Not a setter method");
        }
        index += 3;
        return StringUtils.uncapitalize(this.writeMethod.getName().substring(index));
    }
    else {
        throw new IllegalStateException("Property is neither readable nor writeable");
    }
}

/**
	 * The property type: e.g. {@code java.lang.String}
	 */
public Class<?> getType() {
    return this.methodParameter.getParameterType();
}

  • 从这个方法内容上看,优先使用getter方法的名字作为name的值
  • getter方法可以以getis开头,去掉前缀,第一个字母小写就是name的值
  • setter方法只能以set开头,去掉前缀,第一个字母小写就是name的值

10.4 TypeDescriptor

TypeDescriptorspring定义的类型描述,它里面封装了最终要转换的类型,spring根据这个对象进行类型转换

下面是TypeDescriptor类的属性

public class TypeDescriptor implements Serializable {

    private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];

    //类型描述缓存
    private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);

    private static final Class<?>[] CACHED_COMMON_TYPES = {
        boolean.class, Boolean.class, byte.class, Byte.class, char.class, Character.class,
        double.class, Double.class, float.class, Float.class, int.class, Integer.class,
        long.class, Long.class, short.class, Short.class, String.class, Object.class};

    static {
        for (Class<?> preCachedClass : CACHED_COMMON_TYPES) {
            commonTypesCache.put(preCachedClass, valueOf(preCachedClass));
        }
    }


    //最终要转换的类型
    private final Class<?> type;

    //类型解析器
    private final ResolvableType resolvableType;

    private final AnnotatedElementAdapter annotatedElement;
}

10.4.1 构造方法

/**
 * Create a new type descriptor from a {@link Property}.
 * <p>Use this constructor when a source or target conversion point is a
 * property on a Java class.
 * @param property the property
 */
public TypeDescriptor(Property property) {
    Assert.notNull(property, "Property must not be null");
    //获取解析当前方法参数的类型解析器
    this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
    /**
     * 类型解析器解析方法参数的类型
     * 上一步调用forMethodParameter的时候就已经将类型解析出来了
     * 例如解析List<User>这种属性,它的类型是java.util.List<com.lx.converter.domain.User>
     * 这一步只不过验证是否解析成功,解析成功使用上一步解析出来的resolved,
     * 否则使用property.getType()(最终使用标准反射获取MethodParameter的类型)
     */
    this.type = this.resolvableType.resolve(property.getType());
    //属性注解信息
    this.annotatedElement = new AnnotatedElementAdapter(property.getAnnotations());
}

ResolvableType类型解析器,里面有两个关键属性。

public class ResolvableType implements Serializable {

    /**
     * The underlying Java type being managed.
     * 这个会保存泛型信息
     * 例如解析List<User>这种属性,它里面会保存java.util.List<com.lx.converter.domain.User>
     */
    private final Type type;


    /**
     * 保存的是最终被转换的类型的clazz对象
     * 例如解析List<User>这种属性,它的值就是java.util.List.class
     */
    @Nullable
    private Class<?> resolved;

    /**
     * Resolve this type to a {@link java.lang.Class}, returning the specified
     * {@code fallback} if the type cannot be resolved. This method will consider bounds
     * of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
     * direct resolution fails; however, bounds of {@code Object.class} will be ignored.
     * @param fallback the fallback class to use if resolution fails
     * @return the resolved {@link Class} or the {@code fallback}
     * @see #resolve()
     * @see #resolveGeneric(int...)
     * @see #resolveGenerics()
     */
    public Class<?> resolve(Class<?> fallback) {
        //这一步只不过验证是否解析成功,解析成功使用解析出来的resolved,
        //否则使用property.getType()(最终使用标准反射获取MethodParameter的类型)
        return (this.resolved != null ? this.resolved : fallback);
    }
}

10.4.2 getElementTypeDescriptor()方法,获取类型中的元素类型

/**
 * If this type is an array, returns the array's component type.
 * If this type is a {@code Stream}, returns the stream's component type.
 * If this type is a {@link Collection} and it is parameterized, returns the Collection's element type.
 * If the Collection is not parameterized, returns {@code null} indicating the element type is not declared.
 * @return the array component type or Collection element type, or {@code null} if this type is not
 * an array type or a {@code java.util.Collection} or if its element type is not parameterized
 * @see #elementTypeDescriptor(Object)
 */
@Nullable
public TypeDescriptor getElementTypeDescriptor() {
    if (getResolvableType().isArray()) {
        return new TypeDescriptor(getResolvableType().getComponentType(), null, getAnnotations());
    }
    if (Stream.class.isAssignableFrom(getType())) {
        return getRelatedIfResolvable(this, getResolvableType().as(Stream.class).getGeneric(0));
    }
    return getRelatedIfResolvable(this, getResolvableType().asCollection().getGeneric(0));
}
  • 如果类型是一个数组,那么就返回数组的组件类型
  • 如果类型是一个Stream,那么就返回Stream的组件类型
  • 如果类型是一个Collection并且已经参数化了,那么就返回Collection集合元素的类型
  • 其他情况均返回null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值