美文网首页orm
mybatis的反射工具类—MetaObject(反射对象类)

mybatis的反射工具类—MetaObject(反射对象类)

作者: 小胖学编程 | 来源:发表于2021-01-24 10:50 被阅读0次

    mybatis提供了一个底层的反射工具类。我们在业务代码中也可以使用。

    1. 相关API的使用

    MeatObject是Mybatis的工具类,通过MetaObject获取和设置对象的属性值。

    public class TestMetaObject {
        private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    
        private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
        private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();
    
        public static void main(String[] args) {
    
            //第一次读取
            Teca teca = new Teca();
    
            List<Teca.Stu> objects = new ArrayList<>();
            objects.add(new Teca.Stu());
            teca.setName("lili");
            teca.setStus(objects);
    
            MetaObject metaObject = SystemMetaObject.forObject(teca);
            System.out.println("getGetterNames:" + JSON.toJSONString(metaObject.getGetterNames()));
            System.out.println("getSetterNames:" + JSON.toJSONString(metaObject.getSetterNames()));
            System.out.println("name的get方法返回值:" + JSON.toJSONString(metaObject.getGetterType("name")));
            System.out.println("stus的set方法参数值:" + JSON.toJSONString(metaObject.getGetterType("stus")));
            System.out.println("name的hasGetter:" + metaObject.hasGetter("name"));
            //出现:UnsupportedOperationException异常
    //        System.out.println("stus.id(属性为集合)的hasGetter:" + metaObject.hasGetter("stus.id"));
            System.out.println("stu.id(属性为对象)的hasGetter:" + metaObject.hasGetter("stu.id"));
            System.out.println("获取name的属性值:" + metaObject.getValue("name"));
            //重新设置属性值
            metaObject.setValue("name","huahua");
            System.out.println("设置name的属性值:" + metaObject.getValue("name"));
            //设置属性(集合)的元素值
            metaObject.setValue("stus[0].id","001");
            System.out.println("获取stus集合的第一个元素的属性值:"+JSON.toJSONString(metaObject.getValue("stus[0].id")));
            System.out.println("对象的序列化:"+JSON.toJSONString(teca));
        }
    }
    

    返回结果:

    getGetterNames:["stu","price","name","stus"]
    getSetterNames:["stu","price","name","stus"]
    name的get方法返回值:"java.lang.String"
    stus的set方法参数值:"java.util.List"
    name的hasGetter:true
    stu.id(属性为对象)的hasGetter:true
    获取name的属性值:lili
    设置name的属性值:huahua
    获取stus的第一个元素的属性值:"001"
    对象的序列化:{"name":"huahua","price":0.0,"stus":[{"id":"001"}]}
    

    基本的pojo对象:

    @Data
    @ToString
    public class Teca {
    
        private String name;
    
        private double price;
    
        private List<Stu> stus;
    
        private Stu stu;
    
        @Data
        public static class Stu {
            private String id;
        }
    }
    

    2. 参数说明

    参数 说明 默认使用值
    object 待处理的原始对象 业务对象
    objectFactory 创建对象的工厂 new DefaultObjectFactory()
    objectWrapperFactory object是否是wrapper new DefaultObjectWrapperFactory()
    reflectorFactory 反射的工厂类 new DefaultReflectorFactory()

    2.1 注意事项:

    MetaObject提供了一个工具类:

    public final class SystemMetaObject {
    
      public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
      public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
      public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(NullObject.class, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
    
      private SystemMetaObject() {
        // Prevent Instantiation of Static Class
      }
    
      private static class NullObject {
      }
    
      public static MetaObject forObject(Object object) {
        return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
      }
    
    }
    

    当调用SystemMetaObject获取MetaObject对象时,每次均new DefaultReflectorFactory()了一个反射工厂类。

    继续查看:

    public class DefaultReflectorFactory implements ReflectorFactory {
      private boolean classCacheEnabled = true;
      private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();
    
      public DefaultReflectorFactory() {
      }
    
      @Override
      public boolean isClassCacheEnabled() {
        return classCacheEnabled;
      }
    
      @Override
      public void setClassCacheEnabled(boolean classCacheEnabled) {
        this.classCacheEnabled = classCacheEnabled;
      }
    
      @Override
      public Reflector findForClass(Class<?> type) {
        if (classCacheEnabled) {
                // synchronized (type) removed see issue #461
          Reflector cached = reflectorMap.get(type);
          if (cached == null) {
            cached = new Reflector(type);
            reflectorMap.put(type, cached);
          }
          return cached;
        } else {
          return new Reflector(type);
        }
      }
    
    }
    

    这个类并没有做很复杂的操作,就是获取object的type类型,且存储到Map中。当同一个object调用forObject()时,后续调用可以在缓存中获取反射对象。

    但注意:SystemMetaObject方法因为每次均new了一个新的DefaultReflectorFactory工厂。若每次在方法中调用SystemMetaObject.forObject获取MetaObject对象。同一个对象可能不会走缓存。

    推荐做法:DefaultReflectorFactory声明为静态变量:

    public class TestMetaObject {
        private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    
        private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
        private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();
    
        public static void main(String[] args) {
            
            //第一次读取
            Teca teca = new Teca();
    
            List<Teca.Stu> objects = new ArrayList<>();
            objects.add(new Teca.Stu());
            teca.setName("lili");
            teca.setStus(objects);
            MetaObject metaObject = MetaObject.forObject(teca, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
        }
    }
    

    3. 源码分析

    在创建MetaObject对象的时候,就会将传入的Object对象的所有反射对象都缓存起来。后续调用metaObject.setValue等方法时,直接在缓存中获取到反射对象,然后执行反射操作。

    3.1 创建MetaObject对象

    创建MetaObject对象时,选择不同的Wrapper进行包装。

      private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
        this.originalObject = object;
        this.objectFactory = objectFactory;
        this.objectWrapperFactory = objectWrapperFactory;
        this.reflectorFactory = reflectorFactory;
    
       //判断传入的对象是否是ObjectWrapper子类
        if (object instanceof ObjectWrapper) {
          this.objectWrapper = (ObjectWrapper) object;
        } else if (objectWrapperFactory.hasWrapperFor(object)) {  //默认false
          this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
        } else if (object instanceof Map) {   //判断是否是Map
          this.objectWrapper = new MapWrapper(this, (Map) object);
        } else if (object instanceof Collection) {  //判断是否是集合
          this.objectWrapper = new CollectionWrapper(this, (Collection) object);
        } else {   //普通的pojo处理
          this.objectWrapper = new BeanWrapper(this, object);
        }
      }
    

    以普通的pojo为例,创建BeanWrapper对象,在forClass方法中会遍历object的所有方法。获取反射对象。

      public BeanWrapper(MetaObject metaObject, Object object) {
        super(metaObject);
        this.object = object;
        //getReflectorFactory为传入的参数。
        this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
      }
    

    到此处:

      private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
        this.reflectorFactory = reflectorFactory;
        this.reflector = reflectorFactory.findForClass(type);
      }
    

    到达此处,判断缓存中是否存在某对象的解析结果:

    注意:MetaObject.forObject会将object结果缓存起来,后续在使用MetaObject.forObject创建对象时,直接在缓存中获取。

      @Override
      public Reflector findForClass(Class<?> type) {
        if (classCacheEnabled) {
                // synchronized (type) removed see issue #461
          Reflector cached = reflectorMap.get(type);
          if (cached == null) {
            cached = new Reflector(type);
            reflectorMap.put(type, cached);
          }
          return cached;
        } else {
          return new Reflector(type);
        }
      }
    

    若没有存在,则调用new Reflector(type);去创建cache对象。

      public Reflector(Class<?> clazz) {
        type = clazz;
         //解析构造函数
        addDefaultConstructor(clazz);
        //解析get方法
        addGetMethods(clazz);
        //解析set方法
        addSetMethods(clazz);
        //解析Field属性
        addFields(clazz);
        readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
        writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
        for (String propName : readablePropertyNames) {
          caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
        }
        for (String propName : writeablePropertyNames) {
          caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
        }
      }
    

    3.2 解析object所有的set方法

    总方法:

      private void addSetMethods(Class<?> cls) {
        Map<String, List<Method>> conflictingSetters = new HashMap<String, List<Method>>();
        //获取到object所有的方法。
        Method[] methods = getClassMethods(cls);
        //遍历所有Method
        for (Method method : methods) {
          String name = method.getName();
          //判断name是否以set开头
          if (name.startsWith("set") && name.length() > 3) {
            //set方法的参数只有一个
            if (method.getParameterTypes().length == 1) {
              //移除set前缀。且均变成小写
              name = PropertyNamer.methodToProperty(name);
              //将method和name存储到Map集合
              addMethodConflict(conflictingSetters, name, method);
            }
          }
        }
        //将conflictingSetters放入到属性字段(缓存)
        resolveSetterConflicts(conflictingSetters);
      }
    

    2. 删除方法的前缀,获取属性名:

      public static String methodToProperty(String name) {
        if (name.startsWith("is")) {
          name = name.substring(2);
        } else if (name.startsWith("get") || name.startsWith("set")) {  //截取字段
          name = name.substring(3);
        } else {
          throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
        }
        //都转换为小写
        if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
          name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
        }
    
        return name;
      }
    

    3. key为属性名,value是集合:

      private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
        List<Method> list = conflictingMethods.get(name);
        if (list == null) {
          list = new ArrayList<Method>();
          conflictingMethods.put(name, list);
        }
        list.add(method);
      }
    

    4. 将局部变量放入到属性集合中:

      private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
        //遍历缓存的set方法集合
        for (String propName : conflictingSetters.keySet()) {
          List<Method> setters = conflictingSetters.get(propName);
          Method firstMethod = setters.get(0);
          //若是
          if (setters.size() == 1) {
            addSetMethod(propName, firstMethod);
          } else {
            //期待的type为对应get方法的返回值。
            Class<?> expectedType = getTypes.get(propName);
            if (expectedType == null) {
              throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
                  + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +
                  "specification and can cause unpredicatble results.");
            } else {  //conflictingSetters一个name存在多个value时
              Iterator<Method> methods = setters.iterator();
              Method setter = null;
              
              while (methods.hasNext()) {
                Method method = methods.next();
                //寻找:方法只有一个参数,且参数是期待的参数(getXxx方法的返回值)。
                if (method.getParameterTypes().length == 1
                    && expectedType.equals(method.getParameterTypes()[0])) {
                  setter = method;
                  break;
                }
              }
              if (setter == null) {
                throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
                    + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +
                    "specification and can cause unpredicatble results.");
              }
              addSetMethod(propName, setter);
            }
          }
        }
      }
    

    5. 放入到属性变量中

      private void addSetMethod(String name, Method method) {
        if (isValidPropertyName(name)) {
          setMethods.put(name, new MethodInvoker(method));
          Type[] paramTypes = TypeParameterResolver.resolveParamTypes(method, type);
          setTypes.put(name, typeToClass(paramTypes[0]));
        }
      }
    

    3.3 反射设置值

    public class TestMetaObject {
        private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    
        private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
        private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();
    
        public static void main(String[] args) {
    
            //第一次读取
            Teca teca = new Teca();
            MetaObject metaObject = MetaObject.forObject(teca, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
    
            //重新设置属性值
            metaObject.setValue("name","huahua");
        }
    }
    

    设置分词器:

      public void setValue(String name, Object value) {
        //分词器
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
          MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
          if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
            if (value == null && prop.getChildren() != null) {
              // don't instantiate child path if value is null
              return;
            } else {
              metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
            }
          }
          metaValue.setValue(prop.getChildren(), value);
        } else {
          //object的包装器
          objectWrapper.set(prop, value);
        }
      }
    
    分词器的bug.png
      @Override
      public void set(PropertyTokenizer prop, Object value) {
        if (prop.getIndex() != null) {
          Object collection = resolveCollection(prop, object);
          setCollectionValue(prop, collection, value);
        } else {
          //分词器对象、object对象,设置的值
          setBeanProperty(prop, object, value);
        }
      }
    
      private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
        try {
          //在缓存中获取反射对象
          Invoker method = metaClass.getSetInvoker(prop.getName());
          Object[] params = {value};
          try {
            //反射设置值。
            method.invoke(object, params);
          } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
          }
        } catch (Throwable t) {
          throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
        }
      }
    

    推荐阅读

    https://www.cnblogs.com/javadeveloper/archive/2004/01/13/13151682.html

    相关文章

      网友评论

        本文标题:mybatis的反射工具类—MetaObject(反射对象类)

        本文链接:https://www.haomeiwen.com/subject/isuuzktx.html