Mybatis框架基础支持层——反射工具箱之MetaClass

Posted wly1-6

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis框架基础支持层——反射工具箱之MetaClass相关的知识,希望对你有一定的参考价值。

简介:MetaClass是Mybatis对类级别的元信息的封装和处理,通过与属性工具类的结合, 实现了对复杂表达式的解析,实现了获取指定描述信息的功能

public class MetaClass {

    private ReflectorFactory reflectorFactory;
    private Reflector reflector;


    /**
     * 构造函数私有
     */
    private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
        this.reflectorFactory = reflectorFactory;
        this.reflector = reflectorFactory.findForClass(type);
    }

    /**
     * 调用构造方法创建MetaClass
     */
    public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
        return new MetaClass(type, reflectorFactory);
    }

    /**
     * 通过属性名称, 获取属性的MetaClass(解决成员变量是类的情况)
     */
    public MetaClass metaClassForProperty(String name) {
        Class<?> propType = reflector.getGetterType(name);
        return MetaClass.forClass(propType, reflectorFactory);
    }

    public String findProperty(String name) {
        StringBuilder prop = buildProperty(name, new StringBuilder());
        return prop.length() > 0 ? prop.toString() : null;
    }

    public String findProperty(String name, boolean useCamelCaseMapping) {
        if (useCamelCaseMapping) {
            name = name.replace("_", "");
        }
        return findProperty(name);
    }

    public String[] getGetterNames() {
        return reflector.getGetablePropertyNames();
    }

    public String[] getSetterNames() {
        return reflector.getSetablePropertyNames();
    }

    public Class<?> getSetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaClass metaProp = metaClassForProperty(prop.getName());
            return metaProp.getSetterType(prop.getChildren());
        } else {
            return reflector.getSetterType(prop.getName());
        }
    }

    public Class<?> getGetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaClass metaProp = metaClassForProperty(prop);
            return metaProp.getGetterType(prop.getChildren());
        }
        // issue #506. Resolve the type inside a Collection Object
        return getGetterType(prop);
    }

    private MetaClass metaClassForProperty(PropertyTokenizer prop) {
        Class<?> propType = getGetterType(prop);
        return MetaClass.forClass(propType, reflectorFactory);
    }

    private Class<?> getGetterType(PropertyTokenizer prop) {
        Class<?> type = reflector.getGetterType(prop.getName());
        if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
            Type returnType = getGenericGetterType(prop.getName());
            if (returnType instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
                if (actualTypeArguments != null && actualTypeArguments.length == 1) {
                    returnType = actualTypeArguments[0];
                    if (returnType instanceof Class) {
                        type = (Class<?>) returnType;
                    } else if (returnType instanceof ParameterizedType) {
                        type = (Class<?>) ((ParameterizedType) returnType).getRawType();
                    }
                }
            }
        }
        return type;
    }

    private Type getGenericGetterType(String propertyName) {
        try {
            Invoker invoker = reflector.getGetInvoker(propertyName);
            if (invoker instanceof MethodInvoker) {
                Field _method = MethodInvoker.class.getDeclaredField("method");
                _method.setAccessible(true);
                Method method = (Method) _method.get(invoker);
                return TypeParameterResolver.resolveReturnType(method, reflector.getType());
            } else if (invoker instanceof GetFieldInvoker) {
                Field _field = GetFieldInvoker.class.getDeclaredField("field");
                _field.setAccessible(true);
                Field field = (Field) _field.get(invoker);
                return TypeParameterResolver.resolveFieldType(field, reflector.getType());
            }
        } catch (NoSuchFieldException e) {
        } catch (IllegalAccessException e) {
        }
        return null;
    }

    public boolean hasSetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            if (reflector.hasSetter(prop.getName())) {
                MetaClass metaProp = metaClassForProperty(prop.getName());
                return metaProp.hasSetter(prop.getChildren());
            } else {
                return false;
            }
        } else {
            return reflector.hasSetter(prop.getName());
        }
    }

    public boolean hasGetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            if (reflector.hasGetter(prop.getName())) {
                MetaClass metaProp = metaClassForProperty(prop);
                return metaProp.hasGetter(prop.getChildren());
            } else {
                return false;
            }
        } else {
            return reflector.hasGetter(prop.getName());
        }
    }

    public Invoker getGetInvoker(String name) {
        return reflector.getGetInvoker(name);
    }

    public Invoker getSetInvoker(String name) {
        return reflector.getSetInvoker(name);
    }

    /**
     * 解析属性表达式 会去寻找reflector中是否有对应的的属性
     */
    private StringBuilder buildProperty(String name, StringBuilder builder) {
        // 解析属性表达式
        PropertyTokenizer prop = new PropertyTokenizer(name);
        // 是否有子表达式
        if (prop.hasNext()) {
            // 查找对应的属性
            String propertyName = reflector.findPropertyName(prop.getName());
            if (propertyName != null) {
                // 追加属性名
                builder.append(propertyName);
                builder.append(".");
                // 创建对应的 MetaClass 对象
                MetaClass metaProp = metaClassForProperty(propertyName);
                // 解析子表达式, 递归
                metaProp.buildProperty(prop.getChildren(), builder);
            }
        } else {
            // 根据名称查找属性
            String propertyName = reflector.findPropertyName(name);
            if (propertyName != null) {
                builder.append(propertyName);
            }
        }
        return builder;
    }

    public boolean hasDefaultConstructor() {
        return reflector.hasDefaultConstructor();
    }

}

理解了这个方法(递归, 该类中有很多类似的), 就可以很好的对这个类进行理解, 以查找(richType.richProperty)为例:

  1. 通过 PropertyTokenizer 对表达式进行解析, 得到当前的 name = richType,  children = richProperty
  2. 从 reflector 中查找该 richType 属性
  3. 将 richType 添加到 builder 中
  4. 使用 metaClassForProperty 创建 richType 的 MetaClass。
  5. 递归调用自身来处理子表达式

退出的条件就是没有子表达式。 这个就是为了, 我们类中有成员变量是类, 我们可以通过其找到他们的所有类及其属性
注意, 在此过程中, ReflectorFactory 一直是同一个, 而其内部缓存了多个 Reflector 对象。

以上是关于Mybatis框架基础支持层——反射工具箱之MetaClass的主要内容,如果未能解决你的问题,请参考以下文章

带你彻底搞懂MyBatis的底层实现之反射工具箱(reflector)

带你彻底搞懂MyBatis的底层实现之反射工具箱(reflector)

带你彻底搞懂MyBatis的底层实现之类型转换模块

带你彻底搞懂MyBatis的底层实现之类型转换模块

MyBatis源码分析-基础支持层反射模块Reflector/ReflectorFactory

01 Mybatis 整体架构