亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

基礎支持層位于MyBatis整體架構的最底層,支撐著MyBatis的核心處理層,是整個框架的基石。基礎支持層中封裝了多個較為通用的、獨立的模塊。不僅僅為MyBatis提供基礎支撐,也可以在合適的場景中直接復用。

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

反射模塊詳解

  MyBatis在進行參數處理、結果集映射等操作時會使用到大量的反射操作,JAVA中的反射功能雖然強大,但是代碼編寫起來比較復雜且容易出錯,為了簡化反射操作的相關代碼,MyBatis提供了專門的反射模塊,該模塊位于
org.Apache.ibatis.reflection包下,它對常見的反射操作做了進一步的封裝,提供了更加簡潔方便的反射API。

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

1 Reflector

Reflector是反射模塊的基礎,每個Reflector對象都對應一個類,在Reflector中緩存了反射需要使用的類的元信息

1.1 屬性

? 首先來看下Reflector中提供的相關屬性的含義

  // 對應的Class 類型 
  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.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對象。

/**
 * 反射工具箱
 *    測試用例
 */
public class Person {
    private Integer id;
    private String name;
    public Person(Integer id) {
        this.id = id;
    }
    public Person(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

測試

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

1.3 公共的API方法

  然后我們可以看看Reflector中提供的公共的API方法

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

  了解了Reflector對象的基本信息后我們需要如何來獲取Reflector對象呢?在MyBatis中給我們提供了一個ReflectorFactory工廠對象。所以我們先來簡單了解下ReflectorFactory對象,當然你也可以直接new 出來,像上面的案例一樣

2 ReflectorFactory

  ReflectorFactory接口主要實現了對Reflector對象的創建和緩存。

2.1 ReflectorFactory接口的定義

? 接口的定義如下

public interface ReflectorFactory {
  // 檢測該ReflectorFactory是否緩存了Reflector對象
  boolean isClassCacheEnabled();
  // 設置是否緩存Reflector對象
  void setClassCacheEnabled(boolean classCacheEnabled);
  // 創建指定了Class的Reflector對象
  Reflector findForClass(Class<?> type);
}

  然后我們來看看它的具體實現

2.2 DefaultReflectorFactory

? MyBatis只為該接口提供了DefaultReflectorFactory這一個實現類。他與Reflector的關系如下

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

  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);
    }
  }
}
2.3 使用演示
  通過上面的介紹,我們可以具體的來使用下,加深對其的理解,先準備一個JavaBean,
package com.gupaoedu.domain;
public class Student {
    
    public Integer getId() {
        return 6;
    }
    public void setId(Integer id) {
        System.out.println(id);
    }
    public String getUserName() {
        return "張三";
    }
}

  這個Bean我們做了簡單的處理

    @Test
    public void test02() throws Exception{
        ReflectorFactory factory = new DefaultReflectorFactory();
        Reflector reflector = factory.findForClass(Student.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());
    }
帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

3 Invoker

  針對于Class中Field和Method的調用,在MyBatis中封裝了Invoker對象來統一處理(有使用到適配器模式)

3.1 接口說明

/**
 * @author Clinton Begin
 */
public interface Invoker {
  // 執行Field或者Method
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
  // 返回屬性相應的類型
  Class<?> getType();
}

  該接口有對應的三個實現

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

3.2 效果演示

  使用效果演示,還是通過上面的案例來介紹

package com.gupaoedu.domain;
public class Student {
    public Integer getId() {
        System.out.println("讀取id");
        return 6;
    }
    public void setId(Integer id) {
        System.out.println("寫入id:"+id);
    }
    public String getUserName() {
        return "張三";
    }
}

測試代碼

    public void test03() throws Exception{
        ReflectorFactory factory = new DefaultReflectorFactory();
        Reflector reflector = factory.findForClass(Student.class);
        // 獲取構造器 生成對應的對象
        Object o = reflector.getDefaultConstructor().newInstance();
        MethodInvoker invoker1 = (MethodInvoker) reflector.getSetInvoker("id");
        invoker1.invoke(o,new Object[]{999});
        // 讀取
        Invoker invoker2 = reflector.getGetInvoker("id");
        invoker2.invoke(o,null);
    }

 

效果

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

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);
  }
  // ....
}

  效果演示,準備Bean對象

package com.gupaoedu.domain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RichType {
    private RichType richType;
    private String richField;
    private String richProperty;
    private Map richMap = new HashMap();
    private List richList = new ArrayList() {
        {
            add("bar");
        }
    };
    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;
    }
}

 

測試代碼

    @Test
    public void test7(){
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
        System.out.println(meta.hasGetter("richField"));
        System.out.println(meta.hasGetter("richProperty"));
        System.out.println(meta.hasGetter("richList"));
        System.out.println(meta.hasGetter("richMap"));
        System.out.println(meta.hasGetter("richList[0]"));
        System.out.println(meta.hasGetter("richType"));
        System.out.println(meta.hasGetter("richType.richField"));
        System.out.println(meta.hasGetter("richType.richProperty"));
        System.out.println(meta.hasGetter("richType.richList"));
        System.out.println(meta.hasGetter("richType.richMap"));
        System.out.println(meta.hasGetter("richType.richList[0]"));
        // findProperty 智能處理 . 的表達式
        System.out.println(meta.findProperty("richType.richProperty"));
        System.out.println(meta.findProperty("richType.richProperty1"));
        System.out.println(meta.findProperty("richList[0]"));
        System.out.println(Arrays.toString(meta.getGetterNames()));
    }

 

輸出結果

true
true
true
true
true
true
true
true
true
true
true
richType.richProperty
richType.
null
[richType, richProperty, richMap, richList, richField]

5 MetaObject

  我們可以通過MetaObject對象解析復雜的表達式來對提供的對象進行操作。具體的通過案例來演示會更直觀些

    @Test
    public void shouldGetAndSetField() {
        RichType rich = new RichType();
        MetaObject meta = SystemMetaObject.forObject(rich);
        meta.setValue("richField", "foo");
        System.out.println(meta.getValue("richField"));
    }
    @Test
    public void shouldGetAndSetNestedField() {
        RichType rich = new RichType();
        MetaObject meta = SystemMetaObject.forObject(rich);
        meta.setValue("richType.richField", "foo");
        System.out.println(meta.getValue("richType.richField"));
    }
    @Test
    public void shouldGetAndSetMAppairUsingArraySyntax() {
        RichType rich = new RichType();
        MetaObject meta = SystemMetaObject.forObject(rich);
        meta.setValue("richMap[key]", "foo");
        System.out.println(meta.getValue("richMap[key]"));
    }

以上三個方法的輸出結果都是

foo

6 反射模塊應用

  然后我們來看下在MyBatis的核心處理層中的實際應用

6.1 SqlSessionFactory

  在創建SqlSessionFactory操作的時候會完成Configuration對象的創建,而在Configuration中默認定義的ReflectorFactory的實現就是DefaultReflectorFactory對象

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

  然后在解析全局配置文件的代碼中,給用戶提供了ReflectorFactory的擴展,也就是我們在全局配置文件中可以通過<reflectorFactory>標簽來使用我們自定義的ReflectorFactory

6.2 SqlSession

? 無相關操作

6.3 Mapper

? 無相關操作

6.4 執行SQL

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

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

然后在DefaultResultSetHandler的getRowValue方法中在做自動映射的時候

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

繼續跟蹤,在createAutomaticMappings方法中

帶你徹底搞懂MyBatis的底層實現之反射工具箱(reflector)

 

當然還有很多其他的地方在使用反射模塊來完成的相關操作,這些可自行查閱

好了-反射模塊我們就給大家介紹到這里,如果有問題歡迎留言交流,歡迎大家點贊關注

分享到:
標簽:MyBatis
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定