日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

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

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

 

反射模塊詳解

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

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

 

1 Reflector

Reflector是反射模塊的基礎(chǔ),每個(gè)Reflector對象都對應(yīng)一個(gè)類,在Reflector中緩存了反射需要使用的類的元信息

1.1 屬性

? 首先來看下Reflector中提供的相關(guān)屬性的含義

  // 對應(yīng)的Class 類型 
  private final Class<?> type;
  // 可讀屬性的名稱集合 可讀屬性就是存在 getter方法的屬性,初始值為null
  private final String[] readablePropertyNames;
  // 可寫屬性的名稱集合 可寫屬性就是存在 setter方法的屬性,初始值為null
  private final String[] writablePropertyNames;
  // 記錄了屬性相應(yīng)的setter方法,key是屬性名稱,value是Invoker方法
  // 它是對setter方法對應(yīng)Method對象的封裝
  private final Map<String, Invoker> setMethods = new HashMap<>();
  // 屬性相應(yīng)的getter方法
  private final Map<String, Invoker> getMethods = new HashMap<>();
  // 記錄了相應(yīng)setter方法的參數(shù)類型,key是屬性名稱 value是setter方法的參數(shù)類型
  private final Map<String, Class<?>> setTypes = new HashMap<>();
  // 和上面的對應(yīng)
  private final Map<String, Class<?>> getTypes = new HashMap<>();
  // 記錄了默認(rèn)的構(gòu)造方法
  private Constructor<?> defaultConstructor;
  // 記錄了所有屬性名稱的集合
  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

1.2 構(gòu)造方法

? 在Reflector的構(gòu)造器中會(huì)完成相關(guān)的屬性的初始化操作

  // 解析指定的Class類型 并填充上述的集合信息
  public Reflector(Class<?> clazz) {
    type = clazz; // 初始化 type字段
    addDefaultConstructor(clazz);// 設(shè)置默認(rèn)的構(gòu)造方法
    addGetMethods(clazz);// 獲取getter方法
    addSetMethods(clazz); // 獲取setter方法
    addFields(clazz); // 處理沒有g(shù)etter/setter方法的字段
    // 初始化 可讀屬性名稱集合
    readablePropertyNames = getMethods.keySet().toArray(new String[0]);
    // 初始化 可寫屬性名稱集合
    writablePropertyNames = setMethods.keySet().toArray(new String[0]);
    // caseInsensitivePropertyMap記錄了所有的可讀和可寫屬性的名稱 也就是記錄了所有的屬性名稱
    for (String propName : readablePropertyNames) {
      // 屬性名稱轉(zhuǎn)大寫
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writablePropertyNames) {
      // 屬性名稱轉(zhuǎn)大寫
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }

反射我們也可以在項(xiàng)目中我們直接拿來使用,定義一個(gè)普通的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的底層實(shí)現(xiàn)之反射工具箱(reflector)

 

1.3 公共的API方法

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

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

 

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

2 ReflectorFactory

  ReflectorFactory接口主要實(shí)現(xiàn)了對Reflector對象的創(chuàng)建和緩存。

2.1 ReflectorFactory接口的定義

? 接口的定義如下

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

  然后我們來看看它的具體實(shí)現(xiàn)

2.2 DefaultReflectorFactory

? MyBatis只為該接口提供了DefaultReflectorFactory這一個(gè)實(shí)現(xiàn)類。他與Reflector的關(guān)系如下

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

 

  DefaultReflectorFactory中的實(shí)現(xiàn),代碼比較簡單,我們直接貼出來

public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true;
  // 實(shí)現(xiàn)對 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 {
      // 沒有開啟緩存就直接創(chuàng)建
      return new Reflector(type);
    }
  }
}
2.3 使用演示
  通過上面的介紹,我們可以具體的來使用下,加深對其的理解,先準(zhǔn)備一個(gè)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 "張三";
    }
}

  這個(gè)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("是否具有默認(rèn)的構(gòu)造器:" + reflector.hasDefaultConstructor());
        System.out.println("Reflector對應(yīng)的Class:" + reflector.getType());
    }
帶你徹底搞懂MyBatis的底層實(shí)現(xiàn)之反射工具箱(reflector)

 

3 Invoker

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

3.1 接口說明

/**
 * @author Clinton Begin
 */
public interface Invoker {
  // 執(zhí)行Field或者M(jìn)ethod
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
  // 返回屬性相應(yīng)的類型
  Class<?> getType();
}

  該接口有對應(yīng)的三個(gè)實(shí)現(xiàn)

帶你徹底搞懂MyBatis的底層實(shí)現(xiàn)之反射工具箱(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);
        // 獲取構(gòu)造器 生成對應(yīng)的對象
        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的底層實(shí)現(xiàn)之反射工具箱(reflector)

 

4 MetaClass

  在Reflector中可以針對普通的屬性操作,但是如果出現(xiàn)了比較復(fù)雜的屬性,比如 private Person person; 這種,我們要查找的表達(dá)式 person.userName.針對這種表達(dá)式的處理,這時(shí)就可以通過MetaClass來處理了。我們來看看主要的屬性和構(gòu)造方法

/**
 * 通過 Reflector 和 ReflectorFactory 的組合使用 實(shí)現(xiàn)對復(fù)雜的屬性表達(dá)式的解析
 * @author Clinton Begin
 */
public class MetaClass {
  // 緩存 Reflector
  private final ReflectorFactory reflectorFactory;
  // 創(chuàng)建 MetaClass時(shí) 會(huì)指定一個(gè)Class reflector會(huì)記錄該類的相關(guān)信息
  private final Reflector reflector;
  private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
    this.reflectorFactory = reflectorFactory;
    this.reflector = reflectorFactory.findForClass(type);
  }
  // ....
}

  效果演示,準(zhǔn)備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 智能處理 . 的表達(dá)式
        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()));
    }

 

輸出結(jié)果

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

5 MetaObject

  我們可以通過MetaObject對象解析復(fù)雜的表達(dá)式來對提供的對象進(jìn)行操作。具體的通過案例來演示會(huì)更直觀些

    @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]"));
    }

以上三個(gè)方法的輸出結(jié)果都是

foo

6 反射模塊應(yīng)用

  然后我們來看下在MyBatis的核心處理層中的實(shí)際應(yīng)用

6.1 SqlSessionFactory

  在創(chuàng)建SqlSessionFactory操作的時(shí)候會(huì)完成Configuration對象的創(chuàng)建,而在Configuration中默認(rèn)定義的ReflectorFactory的實(shí)現(xiàn)就是DefaultReflectorFactory對象

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

 

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

6.2 SqlSession

? 無相關(guān)操作

6.3 Mapper

? 無相關(guān)操作

6.4 執(zhí)行SQL

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

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

 

然后在DefaultResultSetHandler的getRowValue方法中在做自動(dòng)映射的時(shí)候

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

 

繼續(xù)跟蹤,在createAutomaticMappings方法中

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

 

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

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

分享到:
標(biāo)簽:MyBatis
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

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

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定