[TOC]java
在以前的代碼中咱們的運行過程再梳理一下,首先咱們執行Test,調用dao接口方法sql
接口的定義:數據庫
調用接口的實現類方法:session
最後纔是調用真正的sql:mybatis
上面的代碼是在接口實現類裏面本身去執行id,查找並執行mapper文件裏面的sql,那麼咱們想是否是能夠減小一步呢?app
若是咱們不用本身實現接口,只須要將接口的名字和mapper文件的namespace對應起來,將接口裏面的方法名與sql語句標籤的id對應起來是否是就能夠了呢?框架
事實上,mybatis提供了這樣的作法,這就是mapper動態代理。學習
首先主配置文件(Mybatis.xml
),在裏面配置數據庫鏈接信息,註冊須要掃描的mapper
文件:this
定義數據庫查詢的接口,裏面每個接口的名字很重要,須要和mapper
裏面每一條sql
對應起來:spa
定義mapper
文件(namespace是接口的全限定類名):
那咱們在使用的時候,須要使用sqlSession.getMapper()
方法,裏面傳入的是接口,意思是經過接口的全限定名,也就是前面在mapper.xml
文件裏面配置的命名空間nameSpace
,這樣一來,就是獲取到了代理類,將dao
和mapper.xml
文件關聯起來了,而每條sql
的id
與咱們的接口方法名字對應起來)
咱們在前面還寫到過一個selectStudentMap()
方法,可是裏面調用的是和SelectList()
同樣的sql
,在接口的實現類裏面咱們本身處理了一下,可是如今使用自動實現的話,底層只會調用SelectOne()
或者SelectList()
方法,因此這個方法會報錯,若是接受類型是list
,那麼框架會自動使用selectList()
方法,不然就會選擇selectOne()
這個方法。
在這裏咱們使用的是返回的是map
,因此自動選擇返回selectOne()
方法,那麼就會報錯。若是咱們須要使用自動返回map
的話,能夠本身定一個map
,或者返回list
以後再處理,這個知識點後面再介紹,有興趣能夠訪問:mybatis的mapper返回map結果集
打一個斷點在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
。
【做者簡介】:
秦懷,公衆號【秦懷雜貨店】做者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。這個世界但願一切都很快,更快,可是我但願本身能走好每一步,寫好每一篇文章,期待和大家一塊兒交流。
此文章僅表明本身(本菜鳥)學習積累記錄,或者學習筆記,若有侵權,請聯繫做者覈實刪除。人無完人,文章也同樣,文筆稚嫩,在下不才,勿噴,若是有錯誤之處,還望指出,感激涕零~