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

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

 更新時間:2022年07月18日 08:17:39   作者:共飲一杯無  
這篇文章主要為大家詳細介紹了MyBatis中Mapper代理的方式,文中將通過源碼為大家進行詳細的剖析,感興趣的小伙伴可以跟隨小編一起學(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);

思考?個問題,通常的Mapper接?我們都沒有實現(xiàn)的?法卻可以使?,是為什么呢? 答案很簡單:動態(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初始化時對接?的處理:MapperRegistry是Configuration中的?個屬性,它內(nèi)部維護?個HashMap?于存放mapper接?的??類,每個接?對應(yīng)?個??類。mappers中可以配置接?的包路徑,或者某個具體的接?類。

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

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

源碼剖析-getmapper()

進? 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通過動態(tài)代理???成實例
      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動態(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 類,實現(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,說明每個session中的代理對象的不同的!  
  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }
  
   //省略部分源碼
}

源碼剖析-invoke()

在動態(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ào)?了MapperMethod執(zhí)?的?法
    return mapperMethod.execute(sqlSession, args);
  }
}

進?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 進?處理
        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í)?查詢,返回單個對象
        } 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不兼容問題的解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Java Convert Kotlin空指針異常的解決方法

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

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

    Java集合之Comparable和Comparator接口詳解

    Java提供了Comparable接口與Comparator接口,它們?yōu)閿?shù)組或集合中的元素提供了排序邏輯,實現(xiàn)此接口的對象數(shù)組或集合可以通過Arrays.sort或Collections.sort進行自動排序。本文將通過示例講講它們的使用,需要的可以參考一下
    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生成字母驗證碼

    使用java生成字母驗證碼

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

    Spring基于XML配置AOP詳解

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

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

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

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

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

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

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

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

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

最新評論

习水县| 西乌| 兴隆县| 雅江县| 宿松县| 黄山市| 武冈市| 合江县| 炉霍县| 双牌县| 齐齐哈尔市| 永吉县| 无为县| 苍山县| 闽清县| 葵青区| 准格尔旗| 左云县| 屏东市| 密云县| 依安县| 汉沽区| 连州市| 鄂托克前旗| 祥云县| 宜宾市| 晋中市| 长寿区| 广宗县| 宜丰县| 榆树市| 郁南县| 墨脱县| 池州市| 连州市| 合水县| 平原县| 麻城市| 临猗县| 盖州市| 敦化市|