07.04 Mybatis Mapper動態代理

事實上,mybatis提供了這樣的做法,我們不用自己實現接口,只需要將接口的名字和mapper文件的namespace對應起來,將接口裡面的方法名與sql語句標籤的id對應起來,這就是mapper動態代理。

mapper動態代理的例子

首先主配置文件(Mybatis.xml),在裡面配置數據庫連接信息,註冊需要掃描的mapper文件:

Mybatis Mapper動態代理

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

Mybatis Mapper動態代理

定義mapper文件(namespace要寫我們定義的接口,而每條sql的id與我們的接口方法名字對應起來):

Mybatis Mapper動態代理

那我們在使用的時候:

Mybatis Mapper動態代理

我們在前面還寫到過一個selectStudentMap方法,但是裡面調用的是和SelectList一樣的sql,在接口的實現類裡面我們自己處理了一下,但是現在使用自動實現的話,底層只會調用SelectOne或者SelectList方法,所以這個方法會報錯,如果接受類型是list,那麼框架會自動使用selectList方法,否則就會選擇selectOne()這個方法。

在這裡我們使用的是返回的是map,所以自動選擇返回selectOne()方法,那麼就會報錯。如果我們需要使用自動返回map的話,可以自己定一個map,或者返回list之後再處理。

mapper動態代理的原理

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

Mybatis Mapper動態代理

我們可以看到執行下面的接口方法(接口SqlSession的方法)

 T getMapper(Class var1);

這是一個接口,我們可以看到實現接口的有兩個類,一個是DefaultSqlSession,一個是SqlSessionManager,我們需要看的是DefaultSqlSession下面的接口:

public T getMapper(Class type) {

return this.configuration.getMapper(type, this);

}

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

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

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

public T getMapper(Class type, SqlSession sqlSession) {

final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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 mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

從下面的debug結果中我們可以看到,這是動態代理的結果:

Mybatis Mapper動態代理

好了,具體內容已經介紹完畢,喜歡的寶寶可以點擊關注,更多精彩內容關注尚學堂喲!

Mybatis Mapper動態代理


分享到:


相關文章: