Mybatis【11】-- Mybatis Mapper動態代理怎麼寫?

1.回顧Mybatis執行sql的流程

在以前的代碼中咱們的運行過程再梳理一下,首先咱們執行Test,調用dao接口方法java

接口的定義:
sql

調用接口的實現類方法:
數據庫

最後纔是調用真正的sql:
session

上面的代碼是在接口實現類裏面本身去執行id,查找並執行mapper文件裏面的sql,那麼咱們想是否是能夠減小一步呢?mybatis

若是咱們不用本身實現接口,只須要將接口的名字和mapper文件的namespace對應起來,將接口裏面的方法名與sql語句標籤的id對應起來是否是就能夠了呢?app

事實上,mybatis提供了這樣的作法,這就是mapper動態代理。框架

2.mapper動態代理怎麼寫?

首先主配置文件(Mybatis.xml),在裏面配置數據庫鏈接信息,註冊須要掃描的mapper文件:學習

定義數據庫查詢的接口,裏面每個接口的名字很重要,須要和mapper裏面每一條sql對應起來:this

定義mapper文件(namespace是接口的全限定類名):
spa

那咱們在使用的時候,須要使用sqlSession.getMapper()方法,裏面傳入的是接口,意思是經過接口的全限定名,也就是前面在mapper.xml文件裏面配置的命名空間nameSpace,這樣一來,就是獲取到了代理類,將daomapper.xml文件關聯起來了,而每條sqlid與咱們的接口方法名字對應起來)

咱們在前面還寫到過一個selectStudentMap()方法,可是裏面調用的是和SelectList()同樣的sql,在接口的實現類裏面咱們本身處理了一下,可是如今使用自動實現的話,底層只會調用SelectOne()或者SelectList()方法,因此這個方法會報錯,若是接受類型是list,那麼框架會自動使用selectList()方法,不然就會選擇selectOne()這個方法。

在這裏咱們使用的是返回的是map,因此自動選擇返回selectOne()方法,那麼就會報錯。若是咱們須要使用自動返回map的話,能夠本身定一個map,或者返回list以後再處理,這個知識點後面再介紹,有興趣能夠訪問:mybatis的mapper返回map結果集

3.mapper動態代理怎麼作的?

打一個斷點在sqlSession.getMapper()方法上:

咱們能夠看到執行下面的接口方法(接口SqlSession的方法)

<T> T getMapper(Class<T> var1);

這是一個接口,咱們能夠看到實現接口的有兩個類,一個是DefaultSqlSession,一個是SqlSessionManager,咱們須要看的是DefaultSqlSession下面的接口:

public <T> T getMapper(Class<T> type) {
    return this.configuration.getMapper(type, this);
  }

咱們知道,在建立sqlsession的時候,confiiguration這個配置對象已經建立完成。跟進去,這是使用mapper註冊器對象的getMapper()方法,將當前的sqlSession對象傳遞進去:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

咱們跟進去源碼,能夠發現裏面使用knownMappers.get(type)來獲取mapper代理工廠,這個konwnMappers是一個hashMap,這個hashMap裏面已經初始化了mapperProxyFactory對象了,獲取到工廠對象以後,再去使用sqlSession實例化:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

實例化的時候,使用了mapper動態代理:

public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

從下面的debug結果中咱們能夠看到,這是動態代理的結果,咱們看到的是dao,可是動態代理對這個dao作了加強,實則是一個mapperProxy

【做者簡介】
秦懷,公衆號【秦懷雜貨店】做者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。這個世界但願一切都很快,更快,可是我但願本身能走好每一步,寫好每一篇文章,期待和大家一塊兒交流。

此文章僅表明本身(本菜鳥)學習積累記錄,或者學習筆記,若有侵權,請聯繫做者覈實刪除。人無完人,文章也同樣,文筆稚嫩,在下不才,勿噴,若是有錯誤之處,還望指出,感激涕零~

相關文章
相關標籤/搜索