<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      MyBatis反射模塊源碼分析

      說明:本文參考至https://www.jianshu.com/p/baba62bbc107

      MyBatis 在進行參數處理、結果映射時等操作時,會涉及大量的反射操作。為了簡化這些反射相關操作,MyBatisorg.apache.ibatis.reflection 包下提供了專門的反射模塊,對反射操作做了近一步封裝,提供了更為簡潔的 API

      一. Reflector

      MyBatis 提供 Reflector 類來緩存類的字段名和 getter/setter 方法的元信息,使得涉及反射的操作時不用再去獲取這些元信息,使操作更加便捷。使用方式是將原始類對象傳入其構造方法,生成 Reflector 對象。

      public class Reflector {
      
        private final Class<?> type;
        //可讀的屬性名稱
        private final String[] readablePropertyNames;
        //可寫的屬性名稱
        private final String[] writablePropertyNames;
        //set方法的屬性
        private final Map<String, Invoker> setMethods = new HashMap<>();
        //get方法的屬性
        private final Map<String, Invoker> getMethods = new HashMap<>();
        //setter類型的列表
        private final Map<String, Class<?>> setTypes = new HashMap<>();
        //getter類型的列表
        private final Map<String, Class<?>> getTypes = new HashMap<>();
        //默認的構造函數
        private Constructor<?> defaultConstructor;
      
        //不區分大小寫的屬性映射
        private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
      
        public Reflector(Class<?> clazz) {
          type = clazz;
          //加入無參構造器
          addDefaultConstructor(clazz);
          //加入getter方法
          addGetMethods(clazz);
          //加入setter方法
          addSetMethods(clazz);
          //加入字段
          addFields(clazz);
          readablePropertyNames = getMethods.keySet().toArray(new String[0]);
          writablePropertyNames = setMethods.keySet().toArray(new String[0]);
          for (String propName : readablePropertyNames) {
            caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
          }
          for (String propName : writablePropertyNames) {
            caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
          }
        }
        
         ...
      }
      

      addGetMethodsaddSetMethods 分別獲取類的所有方法,從符合 getter/setter 規范的方法中解析出字段名,并記錄方法的參數類型、返回值類型等信息:

      /**
       * 注意博主這個版本是3.5.5-SNAPSHOT,采用的是Java8提供的流式操作,老版本的MyBatis源碼和它不一樣,但是功能上是一致的
       * @param clazz
       */
      private void addGetMethods(Class<?> clazz) {
        Map<String, List<Method>> conflictingGetters = new HashMap<>();
        Method[] methods = getClassMethods(clazz);
        Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
          .forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
        resolveGetterConflicts(conflictingGetters);
      }
      

      getter/setter 方法進行去重是通過類似 java.lang.String#getSignature:java.lang.reflect.Method 的方法簽名來實現的,如果子類在實現過程中,參數、返回值使用了不同的類型(使用原類型的子類),則會導致方法簽名不一致,同一字段就會對應不同的 getter/setter 方法,因此需要進行去重。

      private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
        for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
          Method winner = null;
          // 屬性名
          String propName = entry.getKey();
          for (Method candidate : entry.getValue()) {
            if (winner == null) {
              winner = candidate;
              continue;
            }
            // 字段對應了多個get方法
            Class<?> winnerType = winner.getReturnType();
            Class<?> candidateType = candidate.getReturnType();
            if (candidateType.equals(winnerType)) {
              // 返回值類型相同
              if (!boolean.class.equals(candidateType)) {
                throw new ReflectionException(
                    "Illegal overloaded getter method with ambiguous type for property "
                        + propName + " in class " + winner.getDeclaringClass()
                        + ". This breaks the JavaBeans specification and can cause unpredictable results.");
              } else if (candidate.getName().startsWith("is")) {
                // 返回值為boolean的get方法可能有多個,如getIsSave和isSave,優先取is開頭的
                winner = candidate;
              }
            } else if (candidateType.isAssignableFrom(winnerType)) {
              // OK getter type is descendant
              // 可能會出現接口中的方法返回值是List,子類實現方法返回值是ArrayList,使用子類返回值方法
            } else if (winnerType.isAssignableFrom(candidateType)) {
              winner = candidate;
            } else {
              throw new ReflectionException(
                  "Illegal overloaded getter method with ambiguous type for property "
                      + propName + " in class " + winner.getDeclaringClass()
                      + ". This breaks the JavaBeans specification and can cause unpredictable results.");
            }
          }
          // 記錄字段名對應的get方法對象和返回值類型
          addGetMethod(propName, winner);
        }
      }
      

      去重的方式是使用更規范的方法以及使用子類的方法。在確認字段名對應的唯一 getter/setter 方法后,記錄方法名對應的方法、參數、返回值等信息。MethodInvoker 可用于調用 Method 類的 invoke 方法來執行 getter/setter 方法(addSetMethods 記錄映射關系的方式與 addGetMethods 大致相同)。

      private void addFields(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
          if (!setMethods.containsKey(field.getName())) {
            // issue #379 - removed the check for final because JDK 1.5 allows
            // modification of final fields through reflection (JSR-133). (JGB)
            // pr #16 - final static can only be set by the classloader
            int modifiers = field.getModifiers();
            if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
              // 非final的static變量,沒有set方法,可以通過File對象做賦值操作
              addSetField(field);
            }
          }
          if (!getMethods.containsKey(field.getName())) {
            addGetField(field);
          }
        }
        if (clazz.getSuperclass() != null) {
          // 遞歸查找父類
          addFields(clazz.getSuperclass());
        }
      }
      

      二. Invoker

      Invoker 接口用于抽象設置和讀取字段值的操作。對于有 getter/setter 方法的字段,通過 MethodInvoker 反射執行;對應其它字段,通過 GetFieldInvokerSetFieldInvoker 操作 Field 對象的 getter/setter 方法反射執行。

      /**
       * 用于抽象設置和讀取字段值的操作
       *
       * {@link MethodInvoker} 反射執行getter/setter方法
       * {@link GetFieldInvoker} {@link SetFieldInvoker} 反射執行Field對象的get/set方法
       *
       * @author Clinton Begin
       */
      public interface Invoker {
      
        /**
         * 通過反射設置或讀取字段值
         *
         * @param target
         * @param args
         * @return
         * @throws IllegalAccessException
         * @throws InvocationTargetException
         */
        Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
      
        /**
         * 字段類型
         *
         * @return
         */
        Class<?> getType();
      }
      

      三. TypeParameterResolver

      針對 Java-Type 體系的多種實現,TypeParameterResolver 提供一系列方法來解析指定類中的字段、方法返回值或方法參數的類型。

      Type 接口包含 4 個子接口和 1 個實現類:

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4RaVMfK5-1588231783205)(…/images/35.png)]

      • Class:原始類型
      • ParameterizedType:泛型類型,如:List<String>
      • TypeVariable:泛型類型變量,如: List<T> 中的 T
      • GenericArrayType:組成元素是 ParameterizedTypeTypeVariable 的數組類型,如:List<String>[]T[]
      • WildcardType:通配符泛型類型變量,如:List<?> 中的 ?

      TypeParameterResolver 分別提供 resolveFieldTyperesolveReturnTyperesolveParamTypes 方法用于解析字段類型、方法返回值類型和方法入參類型,這些方法均調用 resolveType 來獲取類型信息:

      /**
       * 獲取類型信息
       *
       * @param type 根據是否有泛型信息簽名選擇傳入泛型類型或簡單類型
       * @param srcType 引用字段/方法的類(可能是子類,字段和方法在父類聲明)
       * @param declaringClass 字段/方法聲明的類
       * @return
       */
      private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
        if (type instanceof TypeVariable) {
          // 泛型類型變量,如:List<T> 中的 T
          return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
        } else if (type instanceof ParameterizedType) {
          // 泛型類型,如:List<String>
          return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
        } else if (type instanceof GenericArrayType) {
          // TypeVariable/ParameterizedType 數組類型
          return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
        } else {
          // 原始類型,直接返回
          return type;
        }
      }
      

      resolveTypeVar 用于解析泛型類型變量參數類型,如果字段或方法在當前類中聲明,則返回泛型類型的上界或 Object 類型;如果在父類中聲明,則遞歸解析父類;父類也無法解析,則遞歸解析實現的接口。

      private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
        Type result;
        Class<?> clazz;
        if (srcType instanceof Class) {
          // 原始類型
          clazz = (Class<?>) srcType;
        } else if (srcType instanceof ParameterizedType) {
          // 泛型類型,如 TestObj<String>
          ParameterizedType parameterizedType = (ParameterizedType) srcType;
          // 取原始類型TestObj
          clazz = (Class<?>) parameterizedType.getRawType();
        } else {
          throw new IllegalArgumentException("The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
        }
      
        if (clazz == declaringClass) {
          // 字段就是在當前引用類中聲明的
          Type[] bounds = typeVar.getBounds();
          if (bounds.length > 0) {
            // 返回泛型類型變量上界,如:T extends String,則返回String
            return bounds[0];
          }
          // 沒有上界返回Object
          return Object.class;
        }
      
        // 字段/方法在父類中聲明,遞歸查找父類泛型
        Type superclass = clazz.getGenericSuperclass();
        result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
        if (result != null) {
          return result;
        }
      
        // 遞歸泛型接口
        Type[] superInterfaces = clazz.getGenericInterfaces();
        for (Type superInterface : superInterfaces) {
          result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
          if (result != null) {
            return result;
          }
        }
        return Object.class;
      }
      

      通過調用 scanSuperTypes 實現遞歸解析:

      private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
        if (superclass instanceof ParameterizedType) {
          // 父類是泛型類型
          ParameterizedType parentAsType = (ParameterizedType) superclass;
          Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
          // 父類中的泛型類型變量集合
          TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
          if (srcType instanceof ParameterizedType) {
            // 子類可能對父類泛型變量做過替換,使用替換后的類型
            parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
          }
          if (declaringClass == parentAsClass) {
            // 字段/方法在當前父類中聲明
            for (int i = 0; i < parentTypeVars.length; i++) {
              if (typeVar == parentTypeVars[i]) {
                // 使用變量對應位置的真正類型(可能已經被替換),如父類 A<T>,子類 B extends A<String>,則返回String
                return parentAsType.getActualTypeArguments()[i];
              }
            }
          }
          // 字段/方法聲明的類是當前父類的父類,繼續遞歸
          if (declaringClass.isAssignableFrom(parentAsClass)) {
            return resolveTypeVar(typeVar, parentAsType, declaringClass);
          }
        } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
          // 父類是原始類型,繼續遞歸父類
          return resolveTypeVar(typeVar, superclass, declaringClass);
        }
        return null;
      }
      

      解析方法返回值和方法參數的邏輯大致與解析字段類型相同,MyBatis 源碼的TypeParameterResolverTest 類提供了相關的測試用例。

      四. ReflectorFactory

      MyBatis 還提供 ReflectorFactory 接口用于創建 Reflector 容器,其默認實現為 DefaultReflectorFactory,其中可以使用 classCacheEnabled 屬性來配置是否使用緩存。

      public class DefaultReflectorFactory implements ReflectorFactory {
      
        /**
         * 是否緩存Reflector類信息
         */
        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;
        }
      
        /**
         * 獲取類的Reflector信息
         *
         * @param type
         * @return
         */
        @Override
        public Reflector findForClass(Class<?> type) {
          if (classCacheEnabled) {
            //如果開啟了緩存機制,則嘗試從緩存中拿,如果沒有則創建一個
            return reflectorMap.computeIfAbsent(type, Reflector::new);
          } else {
            return new Reflector(type);
          }
        }
      
      }
      

      五. ObjectFactory

      ObjectFactory 接口是 MyBatis 對象創建工廠,其默認實現 DefaultObjectFactory 通過構造器反射創建對象,支持使用無參構造器和有參構造器。

      六. Property 工具集

      MyBatis 在映射文件定義 resultMap 支持如下形式:

      <resultMap id="map" type="Order">
          <result property="orders[0].items[0].name" column="col1"/>
          <result property="orders[0].items[1].name" column="col2"/>
          ...
      </resultMap>
      

      orders[0].items[0].name 這樣的表達式是由 PropertyTokenizer 解析的,其構造方法能夠對表達式進行解析;同時還實現了 Iterator 接口,能夠迭代解析表達式。

      public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
        private String name;//名稱
        private final String indexedName;//帶索引的名稱
        private String index;//索引
        private final String children;//子名稱
      
        public PropertyTokenizer(String fullname) {
          //找出第一個“.”的索引
          int delim = fullname.indexOf('.');
          if (delim > -1) {
            //存在“.”
            name = fullname.substring(0, delim);
            children = fullname.substring(delim + 1);
          } else {
            //不存在“.”
            name = fullname;
            children = null;
          }
          indexedName = name;
          //第一個“[”的索引
          delim = name.indexOf('[');
          if (delim > -1) {
            index = name.substring(delim + 1, name.length() - 1);
            name = name.substring(0, delim);
          }
        }
        ...
      }
      

      PropertyNamer 可以根據 getter/setter 規范解析字段名稱;PropertyCopier 則支持對有相同父類的對象,通過反射拷貝字段值。

      七. MetaClass

      MetaClass 類依賴 PropertyTokenizerReflector 查找表達式是否可以匹配 Java 對象中的字段,以及對應字段是否有 getter/setter 方法。

      八. ObjectWrapper

      ObjectWrapper是對象的包裝器,提供最基本的get和set方法,不支持多級操作。ObejctWrapper 體系如下:

      在這里插入圖片描述

      ObjectWrapper 的默認實現包括了對 MapCollection 和普通 JavaBean 的包裝。MyBatis 還支持通過 ObjectWrapperFactory 接口對 ObejctWrapper 進行擴展,生成自定義的包裝類。

      例如賦值操作,BeanWrapper 的實現如下:

        @Override
        public Object get(PropertyTokenizer prop) {
          if (prop.getIndex() != null) {
            // 當前表達式是集合,如:items[0],就需要獲取items集合對象
            Object collection = resolveCollection(prop, object);
            return getCollectionValue(prop, collection);
          } else {
            return getBeanProperty(prop, object);
          }
        } 
        @Override
        public void set(PropertyTokenizer prop, Object value) {
          if (prop.getIndex() != null) {
            // 當前表達式是集合,如:items[0],就需要獲取items集合對象
            Object collection = resolveCollection(prop, object);
            // 在集合的指定索引上賦值
            setCollectionValue(prop, collection, value);
          } else {
            // 解析完成,通過Invoker接口做賦值操作
            setBeanProperty(prop, object, value);
          }
        }
      
        protected Object resolveCollection(PropertyTokenizer prop, Object object) {
          if ("".equals(prop.getName())) {
            return object;
          } else {
            // 在對象信息中查到此字段對應的集合對象
            return metaObject.getValue(prop.getName());
          }
        }
      

      九. MetaObject

      相對于 MetaClass 關注類信息,MetalObject 關注的是對象的信息,它在內部包裝了MyBatis中五個核心的反射類。也是提供給外部使用的反射工具類,可以利用它可以讀取或者修改對象的屬性信息:

      public class MetaObject {
      
        //原始對象
        private final Object originalObject;
        //對象的包裝類對象
        private final ObjectWrapper objectWrapper;
        //對象的工廠
        private final ObjectFactory objectFactory;
        //對象包裝器的工廠
        private final ObjectWrapperFactory objectWrapperFactory;
        //反射器工廠
        private final ReflectorFactory reflectorFactory;
      

      MetaObject 對對象的具體操作,就委托給真正的 ObjectWrapper 處理。

      private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
        this.originalObject = object;
        this.objectFactory = objectFactory;
        this.objectWrapperFactory = objectWrapperFactory;
        this.reflectorFactory = reflectorFactory;
      
        if (object instanceof ObjectWrapper) {
          //如果對象本身已經是ObjectWrapper型,則直接賦給objectWrapper
          this.objectWrapper = (ObjectWrapper) object;
        } else if (objectWrapperFactory.hasWrapperFor(object)) {
          //如果有包裝器,調用ObjectWrapperFactory.getWrapperFor
          this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
        } else if (object instanceof Map) {
          //如果是Map型,返回MapWrapper
          this.objectWrapper = new MapWrapper(this, (Map) object);
        } else if (object instanceof Collection) {
          //如果是Collection型,返回CollectionWrapper
          this.objectWrapper = new CollectionWrapper(this, (Collection) object);
        } else {
          //除此以外,返回BeanWrapper
          this.objectWrapper = new BeanWrapper(this, object);
        }
      }
      

      例如賦值操作:

      /**
         * 設置具體值,支持多級操作
         * @param name 屬性名稱,類似于OGNL表達式,如果是多級結構,直接person[0].birthdate.year即可
         * @param value
         */
        public void setValue(String name, Object value) {
          //將name解析為PropertyTokenizer,方便進行對象的賦值
          PropertyTokenizer prop = new PropertyTokenizer(name);
          if (prop.hasNext()) {
            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
              //如果獲取出來的設置空的MetaObject
              if (value == null) {
                // 如果值為空,則不會實例化子路徑
                return;
              } else {
                //如果value不為空,則委派給ObjectWrapper.instantiatePropertyValue創建子級對象并獲取子級對象的MetaObject
                metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
              }
            }
            //繼續給子節點賦值(偽遞歸)
            metaValue.setValue(prop.getChildren(), value);
          } else {
            //到了最后一層了,最終還是委派給ObjectWrapper.set
            objectWrapper.set(prop, value);
          }
        }
      

      十. 測試

      由于MetaObject是MyBatis反射模塊對外提供的反射工具類,所以我們對其進行測試:

      public class Area {
          private String name;
          private Area child;
      }
      
      /**
       *  使用MetaObject工具進行多級賦值測試
       */
      @Test
      public void testMetaObjectForChildBean() {
          //初始化對象工廠
          DefaultObjectFactory objectFactory = new DefaultObjectFactory();
          //通過對象工程創建 Area實例
          Area area = objectFactory.create(Area.class);
          //創建包裝類工廠
          DefaultObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
          //創建反射器工廠
          DefaultReflectorFactory reflectorFactory = new DefaultReflectorFactory();
          //創建MetaObject
          MetaObject metaObject = MetaObject.forObject(area, objectFactory, objectWrapperFactory, reflectorFactory);
          //賦值
          metaObject.setValue("name","湖北省");
          metaObject.setValue("child.name","武漢市");
          metaObject.setValue("child.child.name","洪山區");
      }
      

      在這里插入圖片描述

      其他反射模塊代碼注釋請移步至GitHubGitee

      posted @ 2020-04-30 15:31  聽到微笑  閱讀(25)  評論(0)    收藏  舉報  來源
      主站蜘蛛池模板: 亚洲国产精品无码一区二区三区| 免费萌白酱国产一区二区三区| 国产女人在线视频| 亚洲成av人片无码迅雷下载| 产综合无码一区| 亚洲国产理论片在线播放| 成人午夜视频一区二区无码| 鲜嫩高中生无套进入| 国内久久人妻风流av免费| 左贡县| 美女禁区a级全片免费观看| 一本精品99久久精品77| 精品偷拍一区二区三区| 久久久精品人妻一区二区三区| 迁安市| 国产精品∧v在线观看| 少妇人妻偷人精品一区二| 五月综合激情婷婷六月色窝| 亚洲午夜久久久影院伊人| 一区二区三区四区自拍视频| 开心婷婷五月激情综合社区| 国产日韩av二区三区| 一本色道国产在线观看二区| 91麻豆视频国产一区二区 | 亚洲高清国产拍精品熟女| 久久天天躁狠狠躁夜夜2020老熟妇| 欧美激情一区二区| 英山县| 久久精品国产精品第一区| 2019亚洲午夜无码天堂| 久久精品国产亚洲av麻豆长发| 欧美成人黄在线观看| 最新国内精品自在自线视频| 国产精品第一二三区久久| 永久免费av无码网站直播| 精品久久久久无码| 亚洲va韩国va欧美va| 国产精品久久中文字幕网| 黄梅县| 国产亚洲一二三区精品| 精品国产三级在线观看|