最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis源碼剖析之Mapper代理方式詳解

 更新時(shí)間:2022年07月18日 08:17:39   作者:共飲一杯無  
這篇文章主要為大家詳細(xì)介紹了MyBatis中Mapper代理的方式,文中將通過源碼為大家進(jìn)行詳細(xì)的剖析,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

具體代碼如下:

//前三步都相同
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//這?不再調(diào)?SqlSession的api,?是獲得了接?對象,調(diào)?接?中的?法。
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//模擬ids的數(shù)據(jù)
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
List<User> userList = mapper.findByIds(ids);

思考?個(gè)問題,通常的Mapper接?我們都沒有實(shí)現(xiàn)的?法卻可以使?,是為什么呢? 答案很簡單:動(dòng)態(tài)代理

public class Configuration {  
    protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
}

public class MapperRegistry {
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
}

開始之前介紹?下MyBatis初始化時(shí)對接?的處理:MapperRegistry是Configuration中的?個(gè)屬性,它內(nèi)部維護(hù)?個(gè)HashMap?于存放mapper接?的??類,每個(gè)接?對應(yīng)?個(gè)??類。mappers中可以配置接?的包路徑,或者某個(gè)具體的接?類。

<mappers>
  <mapper class="com.zjq.mapper.UserMapper"/>
  <package name="com.zjq.mapper"/>
</mappers>

當(dāng)解析mappers標(biāo)簽時(shí),它會(huì)判斷解析到的是mapper配置?件時(shí),會(huì)再將對應(yīng)配置?件中的增刪改查標(biāo)簽 封裝成MappedStatement對象,存?mappedStatements中。(上?介紹了)當(dāng)判斷解析到接?時(shí),會(huì)建此接?對應(yīng)的MapperProxyFactory對象,存?HashMap中,key =接?的字節(jié)碼對象,value =此接?對應(yīng)MapperProxyFactory對象。

源碼剖析-getmapper()

進(jìn)? sqlSession.getMapper(UserMapper.class )中

public interface SqlSession extends Closeable {
      //調(diào)用configuration中的getMapper
      <T> T getMapper(Class<T> type);
}

public class DefaultSqlSession implements SqlSession {
  @Override
  public <T> T getMapper(Class<T> type) {
    //調(diào)用configuration 中的getMapper
    return configuration.<T>getMapper(type, this);
  }
}

public class Configuration {
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //調(diào)用MapperRegistry 中的getMapper
    return mapperRegistry.getMapper(type, sqlSession);
  }
}

public class MapperRegistry {
  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //從 MapperRegistry 中的 HashMap 中拿 MapperProxyFactory
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      //調(diào)用MapperProxyFactory的newInstance通過動(dòng)態(tài)代理???成實(shí)例
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
}


public class MapperProxyFactory<T> {
  public T newInstance(SqlSession sqlSession) {
    //創(chuàng)建了 JDK動(dòng)態(tài)代理的Handler類
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    //調(diào)?了重載?法
    return newInstance(mapperProxy);
  }
   
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
}

//MapperProxy 類,實(shí)現(xiàn)了 InvocationHandler 接?
public class MapperProxy<T> implements InvocationHandler, Serializable {
  //省略部分源碼
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;
    
  //構(gòu)造,傳?了 SqlSession,說明每個(gè)session中的代理對象的不同的!  
  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }
  
   //省略部分源碼
}

源碼剖析-invoke()

在動(dòng)態(tài)代理返回了示例后,我們就可以直接調(diào)?mapper類中的?法了,但代理對象調(diào)??法,執(zhí)?是在MapperProxy中的invoke?法中。

public class MapperProxy<T> implements InvocationHandler, Serializable { 
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      //如果是Object定義的?法,直接調(diào)?
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    // 獲得 MapperMethod 對象
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //重點(diǎn)在這:最終調(diào)?了MapperMethod執(zhí)?的?法
    return mapperMethod.execute(sqlSession, args);
  }
}

進(jìn)?execute?法:

public class MapperMethod { 
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判斷mapper中的?法類型,最終調(diào)?的還是SqlSession中的?法 switch(command.getType()) 
    switch (command.getType()) {
      case INSERT: {
        //轉(zhuǎn)換參數(shù)
        Object param = method.convertArgsToSqlCommandParam(args);
        //執(zhí)?INSERT操作
        //轉(zhuǎn)換rowCount
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        //轉(zhuǎn)換參數(shù)
        Object param = method.convertArgsToSqlCommandParam(args);
        // 轉(zhuǎn)換 rowCount
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        //轉(zhuǎn)換參數(shù)
        Object param = method.convertArgsToSqlCommandParam(args);
        // 轉(zhuǎn)換 rowCount
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        //?返回,并且有ResultHandler?法參數(shù),則將查詢的結(jié)果,提交給 ResultHandler 進(jìn)?處理
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        //執(zhí)?查詢,返回列表
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        //執(zhí)?查詢,返回Map
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        //執(zhí)?查詢,返回Cursor
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        //執(zhí)?查詢,返回單個(gè)對象
        } else {
          //轉(zhuǎn)換參數(shù)
          Object param = method.convertArgsToSqlCommandParam(args);
          //查詢單條
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    //返回結(jié)果為null,并且返回類型為基本類型,則拋出BindingException異常
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    //返回結(jié)果
    return result;
  }
}

到此這篇關(guān)于MyBatis源碼剖析之Mapper代理方式詳解的文章就介紹到這了,更多相關(guān)MyBatis Mapper代理方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JPA與mybatis-plus不兼容問題的解決

    JPA與mybatis-plus不兼容問題的解決

    本文主要介紹了JPA與mybatis-plus不兼容問題的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Java Convert Kotlin空指針異常的解決方法

    Java Convert Kotlin空指針異常的解決方法

    本文主要介紹了Java?Convert?Kotlin空指針異常的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Java集合之Comparable和Comparator接口詳解

    Java集合之Comparable和Comparator接口詳解

    Java提供了Comparable接口與Comparator接口,它們?yōu)閿?shù)組或集合中的元素提供了排序邏輯,實(shí)現(xiàn)此接口的對象數(shù)組或集合可以通過Arrays.sort或Collections.sort進(jìn)行自動(dòng)排序。本文將通過示例講講它們的使用,需要的可以參考一下
    2022-12-12
  • Java Socket通信(一)之客戶端程序 發(fā)送和接收數(shù)據(jù)

    Java Socket通信(一)之客戶端程序 發(fā)送和接收數(shù)據(jù)

    對于Socket通信簡述,服務(wù)端往Socket的輸出流里面寫東西,客戶端就可以通過Socket的輸入流讀取對應(yīng)的內(nèi)容,Socket與Socket之間是雙向連通的,所以客戶端也可以往對應(yīng)的Socket輸出流里面寫東西,然后服務(wù)端對應(yīng)的Socket的輸入流就可以讀出對應(yīng)的內(nèi)容
    2016-03-03
  • 使用java生成字母驗(yàn)證碼

    使用java生成字母驗(yàn)證碼

    這篇文章主要介紹了使用java生成字母驗(yàn)證碼的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Spring基于XML配置AOP詳解

    Spring基于XML配置AOP詳解

    這篇文章主要介紹了Spring基于XML配置AOP詳解,Spring 的 AOP 功能是基于 AspectJ 實(shí)現(xiàn)的,支持使用 XML 方式定義 AOP 切面,Spring 項(xiàng)目使用 AOP 功能需要定義三個(gè)部分:切面、切點(diǎn)和通知,需要的朋友可以參考下
    2023-09-09
  • java實(shí)現(xiàn)html轉(zhuǎn)pdf方法步驟

    java實(shí)現(xiàn)html轉(zhuǎn)pdf方法步驟

    這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)html轉(zhuǎn)pdf方法的相關(guān)資料,要將HTML轉(zhuǎn)換成PDF,我們需要借助Java中的第三方庫,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • 如何在Java中調(diào)用python文件執(zhí)行詳解

    如何在Java中調(diào)用python文件執(zhí)行詳解

    豐富的第三方庫使得python非常適合用于進(jìn)行數(shù)據(jù)分析,最近在項(xiàng)目中就涉及到j(luò)ava調(diào)用python實(shí)現(xiàn)的算法,下面這篇文章主要給大家介紹了關(guān)于如何在Java中調(diào)用python文件執(zhí)行的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • java8升級到j(luò)ava17的兼容性分析與遷移指南

    java8升級到j(luò)ava17的兼容性分析與遷移指南

    這篇文章主要為大家詳細(xì)介紹了從?Java?8?升級到?Java?17?的詳細(xì)分析和遷移步驟,包括代碼修改建議,依賴更新和配置調(diào)整,有需要的小伙伴可以參考一下
    2025-04-04
  • java Quartz定時(shí)器任務(wù)與Spring task定時(shí)的幾種實(shí)現(xiàn)方法

    java Quartz定時(shí)器任務(wù)與Spring task定時(shí)的幾種實(shí)現(xiàn)方法

    本篇文章主要介紹了java Quartz定時(shí)器任務(wù)與Spring task定時(shí)的幾種實(shí)現(xiàn)方法的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-02-02

最新評論

涟水县| 信宜市| 剑川县| 稻城县| 芜湖市| 化德县| 天台县| 徐州市| 庆云县| 新安县| 泾川县| 拉萨市| 女性| 出国| 博爱县| 崇仁县| 广昌县| 南昌县| 浑源县| 达尔| 浦江县| 丰镇市| 长治县| 台中县| 宜君县| 浦北县| 双流县| 安远县| 浮山县| 色达县| 青阳县| 大埔县| 昆明市| 夏邑县| 方山县| 陆川县| 东光县| 吉首市| 隆尧县| 新余市| 贵州省|