zoukankan      html  css  js  c++  java
  • mybaits源码分析--反射模块(二)

    1.反射模块

    MyBatis在进行参数处理、结果集映射等操作时会使用到大量的反射操作,Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错,为了简化反射操作的相关代码,MyBatis提供了专门的反射模块,该模块位于org.apache.ibatis.reflection包下,它对常见的反射操作做了进一步的封装,提供了更加简洁方便的反射API。

     1.1 Reflector

    Reflector是反射模块的基础,每个Reflector对象都对应一个类,在Reflector中缓存了反射需要使用的类的元信息

    1.1.1 属性

    首先看下Reflector类中提供的相关属性的含义

      // 对应的Class 类型 1
      private final Class<?> type;
      // 可读属性的名称集合 可读属性就是存在 getter方法的属性,初始值为null
      private final String[] readablePropertyNames;
      // 可写属性的名称集合 可写属性就是存在 setter方法的属性,初始值为null
      private final String[] writablePropertyNames;
      // 记录了属性相应的setter方法,key是属性名称,value是Invoker方法
      // 他是对setter方法对应Method对象的封装
      private final Map<String, Invoker> setMethods = new HashMap<>();
      // 属性相应的getter方法
      private final Map<String, Invoker> getMethods = new HashMap<>();
      // 记录了相应setter方法的参数类型,key是属性名称 value是setter方法的参数类型
      private final Map<String, Class<?>> setTypes = new HashMap<>();
      // 和上面的对应
      private final Map<String, Class<?>> getTypes = new HashMap<>();
      // 记录了默认的构造方法
      private Constructor<?> defaultConstructor;
    
      // 记录了所有属性名称的集合
      private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

    1.1.2 构造方法

    在Reflector的构造器中会完成相关的属性的初始化操作

      // 解析指定的Class类型 并填充上述的集合信息
      public Reflector(Class<?> clazz) {
        type = clazz; // 初始化 type字段
        addDefaultConstructor(clazz);// 设置默认的构造方法
        addGetMethods(clazz);// 获取getter方法
        addSetMethods(clazz); // 获取setter方法
        addFields(clazz); // 处理没有getter/setter方法的字段
        // 初始化 可读属性名称集合
        readablePropertyNames = getMethods.keySet().toArray(new String[0]);
        // 初始化 可写属性名称集合
        writablePropertyNames = setMethods.keySet().toArray(new String[0]);
        // caseInsensitivePropertyMap记录了所有的可读和可写属性的名称 也就是记录了所有的属性名称
        for (String propName : readablePropertyNames) {
          // 属性名称转大写
          caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
        }
        for (String propName : writablePropertyNames) {
          // 属性名称转大写
          caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
        }
      }

    反射我们也可以在项目中我们直接拿来使用,定义一个普通的Bean对象。

     1.1.3 公共的API方法

    然后看看Reflector中提供的公共的API方法

    方法名称 作用
    getType 获取Reflector表示的Class
    getDefaultConstructor 获取默认的构造器
    hasDefaultConstructor 判断是否有默认的构造器
    getSetInvoker 根据属性名称获取对应的Invoker 对象
    getGetInvoker 根据属性名称获取对应的Invoker对象
    getSetterType

    获取属性对应的类型 比如:
    String name; // getSetterType("name") --> java.lang.String

    getGetterType 与上面是对应的
    getGetablePropertyNames 获取所有的可读属性名称的集合
    getSetablePropertyNames 获取所有的可写属性名称的集合
    hasSetter 判断是否具有某个可写的属性
    hasGetter 判断是否具有某个可读的属性
    findPropertyName 根据名称查找属性

    了解了Reflector对象的基本信息后接下需要知道的就是如何来获取Reflector对象,在MyBatis中给我们提供了一个ReflectorFactory工厂对象。所以先来简单了解下ReflectorFactory对象,当然也可以直接new 出来,像上面的案例一样

    1.2 ReflectorFactory

    ReflectorFactory接口主要实现了对Reflector对象的创建和缓存。

    1.2.1 ReflectorFactory接口的定义

    接口的定义如下

    public interface ReflectorFactory {
      // 检测该ReflectorFactory是否缓存了Reflector对象
      boolean isClassCacheEnabled();
      // 设置是否缓存Reflector对象
      void setClassCacheEnabled(boolean classCacheEnabled);
      // 创建指定了Class的Reflector对象
      Reflector findForClass(Class<?> type);
    }

    然后看看它的具体实现

     DefaultReflectorFactory中的实现,代码比较简单

    public class DefaultReflectorFactory implements ReflectorFactory {
      private boolean classCacheEnabled = true;
      // 实现对 Reflector 对象的缓存
      private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
    
      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
          return reflectorMap.computeIfAbsent(type, Reflector::new);
        } else {
          // 没有开启缓存就直接创建
          return new Reflector(type);
        }
      }
    
    }

    1.2.3 使用演示

    public class User implements Serializable {
        private Integer id;
    
        private String userName;
    
        private String realName;
    
        private String password;
    
        private Integer age;
    
        private Integer dId;
    
        private Dept dept;
    
        public Integer getId() {
            return 2;
        }
    
        public void setId(Integer id) {
            System.out.println(id);
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getRealName() {
            return realName;
        }
    
        public void setRealName(String realName) {
            this.realName = realName;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Integer getdId() {
            return dId;
        }
    
        public void setdId(Integer dId) {
            this.dId = dId;
        }
    
        public Dept getDept() {
            return dept;
        }
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    }
        /**
         * ReflectorFactory功能演示
         * @throws Exception
         */
        @Test
        public void test01() throws Exception{
            ReflectorFactory factory=new DefaultReflectorFactory();
            Reflector reflector=factory.findForClass(User.class);
            System.out.println("可读"+ Arrays.toString(reflector.getGetablePropertyNames()));
            System.out.println("可写"+ Arrays.toString(reflector.getSetablePropertyNames()));
            System.out.println("是否有默认构造器"+reflector.hasDefaultConstructor());
            System.out.println("Reflector对应的class"+reflector.getType());
        }

     1.3 Invoker

    针对于Class中Field和Method的调用,在MyBatis中封装了Invoker对象来统一处理(有使用到适配器模式)

    1.3.1 接口说明

    public interface Invoker {
      // 执行Field或者Method
      Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
    
      // 返回属性相应的类型
      Class<?> getType();
    }

    这个接口对应有三个实现

     1.3.2 效果演示

    public class User {
    
        public Integer getId() {
            System.out.println("读取id");
            return 6;
        }
        public void setId(Integer id) {
            System.out.println("写入id:"+id);
        }
        public String getUserName() {
            return "张三";
        }
    }
        @Test
    public void test02() throws Exception{
    ReflectorFactory factory = new DefaultReflectorFactory();
    Reflector reflector = factory.findForClass(User.class);
    //获取构造器 生成对应对象
    Object o = reflector.getDefaultConstructor().newInstance();
    org.apache.ibatis.reflection.invoker.Invoker invoker1=reflector.getSetInvoker("id");
    invoker1.invoke ( o ,new Object[] { 999 });

    /* 读取 */
    org.apache.ibatis.reflection.invoker.Invoker invoker2= reflector.getGetInvoker("id");
    invoker2.invoke( o,null);
    }
    }

     1.4 MetaClass

    在Reflector中可以针对普通的属性操作,但是如果出现了比较复杂的属性,比如 private Person person; 这种,我们要查找的表达式 person.userName.针对这种表达式的处理,这时就可以通过MetaClass来处理了。我们来看看主要的属性和构造方法

    /**
     * 通过 Reflector 和 ReflectorFactory 的组合使用 实现对复杂的属性表达式的解析
     * @author Clinton Begin
     */
    public class MetaClass {
      // 缓存 Reflector
      private final ReflectorFactory reflectorFactory;
      // 创建 MetaClass时 会指定一个Class reflector会记录该类的相关信息
      private final Reflector reflector;
    
      private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
        this.reflectorFactory = reflectorFactory;
        this.reflector = reflectorFactory.findForClass(type);
      }
    
      public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
        return new MetaClass(type, reflectorFactory);
      }
    
      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 | IllegalAccessException ignored) {
        }
        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);
      }
    
      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 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();
      }
    
    }

    效果演示,准备Bean对象

    public class RichType {
        private RichType richType;
        private String richField;
        private String richProperty;
        private Map richMap = new HashMap ();
        private List richList = new ArrayList () {
            {
                add("小家伙要记得学习");
            }
        };
        public RichType getRichType() {
            return richType;
        }
        public void setRichType(RichType richType) {
            this.richType = richType;
        }
        public String getRichProperty() {
            return richProperty;
        }
        public void setRichProperty(String richProperty) {
            this.richProperty = richProperty;
        }
        public List getRichList() {
            return richList;
        }
        public void setRichList(List richList) {
            this.richList = richList;
        }
        public Map getRichMap() {
            return richMap;
        }
        public void setRichMap(Map richMap) {
            this.richMap = richMap;
        }
    }
      /**
         * MetaClass功能演示
         * @throws Exception
         */
        @Test
        public void test03() throws Exception{
            ReflectorFactory factory = new DefaultReflectorFactory();
            MetaClass metaClass=MetaClass.forClass ( RichType.class,factory);
            System.out.println(metaClass.hasGetter("richField"));
            System.out.println(metaClass.hasGetter("richProperty"));
            System.out.println(metaClass.hasGetter("richList"));
            System.out.println(metaClass.hasGetter("richMap"));
            System.out.println(metaClass.hasGetter("richList[0]"));
    
            System.out.println(metaClass.hasGetter("richType"));
            System.out.println(metaClass.hasGetter("richType.richField"));
            System.out.println(metaClass.hasGetter("richType.richProperty"));
            System.out.println(metaClass.hasGetter("richType.richList"));
            System.out.println(metaClass.hasGetter("richType.richMap"));
            System.out.println(metaClass.hasGetter("richType.richList[0]"));
             // findProperty 只能处理 . 的表达式
            System.out.println(metaClass.findProperty("richType.richProperty"));
            System.out.println(metaClass.findProperty("richType.richProperty1"));
            System.out.println(metaClass.findProperty("richList[0]"));
            System.out.println(Arrays.toString(metaClass.getGetterNames()));
        }

    1.5 MetaObject

    可以通过MetaObject对象解析复杂的表达式来对提供的对象进行操作。具体的通过案例来演示会更直观些

        @Test
        public void test04() throws Exception{
            RichType richType=new RichType ();
            MetaObject metaObject=SystemMetaObject.forObject ( richType );
            metaObject.setValue ( "richField","李四" );
            System.out.println (metaObject.getValue ( "richField" ));
        }
        @Test
        public void test05() throws Exception{
            RichType richType=new RichType ();
            MetaObject metaObject=SystemMetaObject.forObject ( richType );
            metaObject.setValue ( "richType.richField","李四1" );
            System.out.println (metaObject.getValue ( "richType.richField" ));
        }
        @Test
        public void test06() throws Exception{
            RichType richType=new RichType ();
            MetaObject metaObject=SystemMetaObject.forObject ( richType );
            metaObject.setValue ( "richMap[0]","李四2" );
            System.out.println (metaObject.getValue ( "richMap[0]" ));
        }

     

     

     1.6 反射模块应用

      看下在MyBatis的核心处理层中的实际应用

    1.6.1 SqlSessionFactory

    在创建SqlSessionFactory操作的时候会完成Configuration对象的创建,而在Configuration中默认定义的ReflectorFactory的实现就是DefaultReflectorFactory对象

          然后在解析全局配置文件的代码中,给用户提供了ReflectorFactory的扩展,也就是我们在全局配置文件中可以通过<reflectorFactory>标签来使用我们自定义的ReflectorFactory

    1.6.2 执行SQL

    在Statement获取结果集后,在做结果集映射的使用有使用到,在DefaultResultSetHandler的createResultObject方法中。

     然后在DefaultResultSetHandler的getRowValue方法中在做自动映射的时候

     继续跟踪,在createAutomaticMappings方法中

    这短短的一生我们最终都会失去,不妨大胆一点,爱一个人,攀一座山,追一个梦
  • 相关阅读:
    centos7 /etc/rc.local需要chmod +x /etc/rc.d/rc.local
    epel源
    yum 源
    socket
    CentOS 7使用systemctl如何补全服务名称
    keepalive脑裂的处理,从节点发现访问的虚拟IP就报警,同时尝试发送内容到主节点服务器关闭keepalive和nginx,或者关机
    nginx的 keepalive_timeout参数是一个请求完成之后还要保持连
    kickstart安装步骤
    kickstart
    因客户机IP与服务器IP不在同一网段导致无盘客户机开机卡tftp,提示:PXE-E11: ARP timeout
  • 原文地址:https://www.cnblogs.com/xing1/p/15206524.html
Copyright © 2011-2022 走看看