手写自己的MyBatis框架-MapperProxy
我們要在Configuration 中通過getMapper()方法拿到這個代理對象,必須要有一個實現(xiàn)了InvocationHandler 的代理類。我們來創(chuàng)建它:MapperProxy。
提供一個invoke()方法。
// MapperProxy.java public class MapperProxy implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return null;} }invoke()的實現(xiàn)我們先留著,先返回null。MapperProxy 已經(jīng)有了,我們回到Configuration.getMapper()完成獲取代理對象的邏輯。
返回代理對象,直接使用JDK 的動態(tài)代理:第一個參數(shù)是類加載器,第二個參數(shù)是被代理類,第三個參數(shù)是代理類。
把返回結(jié)果強轉(zhuǎn)為(T):
Configuration.java public <T> T getMapper(Class<T> clazz, SqlSession sqlSession) {return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{clazz},new MapperProxy()); }獲取代理類的邏輯已經(jīng)實現(xiàn)完了,我們可以在SqlSession 中通過getMapper()拿到代理對象了,也就是可以調(diào)用invoke()方法了。接下來去完成MapperProxy 的invoke()方法。
在MapperProxy 的invoke()方法里面又調(diào)用了SqlSession 的selectOne()方法。一個問題出現(xiàn)了:在MapperProxy 里面根本沒有SqlSession 對象?
這兩個對象的關(guān)系怎么建立起來?MapperProxy 怎么拿到一個SqlSession 對象?
很簡單,我們可通過構(gòu)造函數(shù)傳入它。
先定義一個屬性,然后在MapperProxy 的構(gòu)造函數(shù)里面賦值:
// MapperProxy.java private SqlSession sqlSession; public MapperProxy(SqlSession sqlSession) {this.sqlSession = sqlSession; }因為修改了代理類的構(gòu)造函數(shù),這個時候Configuration 創(chuàng)建代理類的方法getMapper()也要修改。
問題:Configuration 的getMapper()方法參數(shù)中也沒有SqlSession,沒辦法傳給MapperProxy 的構(gòu)造函數(shù)。怎么拿到SqlSession 呢?是直接new 一個嗎?
不需要,可以在SqlSession 調(diào)用它的時候直接把自己傳進來(紅色是修改的地方):
// Configuration.java public <T> T getMapper(Class clazz, SqlSession sqlSession) {return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{clazz},new MapperProxy(sqlSession)); }那么SqlSession 的getMapper()方法也要修改(紅色是修改的地方):
// SqlSession.java public <T> T getMapper(Class clazz){return configuration.getMapper(clazz, this); }現(xiàn)在在MapperProxy 里面已經(jīng)就可以拿到SqlSession 對象了,在invoke()方法里面我們會調(diào)用SqlSession 的selectOne()方法。我們繼續(xù)來完成invoke()方法。
selectOne()方法有兩個參數(shù), statementId 和paramater,這兩個我們怎么拿到呢?
statementId 其實就是接口的全路徑+方法名,中間加一個英文的點。
paramater 可以從方法參數(shù)中拿到,這里我們只傳了一個參數(shù),用args[0]。
它要把statementId 和參數(shù)傳給SqlSession:
// MapperProxy.java public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String mapperInterface = method.getDeclaringClass().getName();String methodName = method.getName();String statementId = mapperInterface + "." + methodName;return sqlSession.selectOne(statementId, args[0]); }?
總結(jié)
以上是生活随笔為你收集整理的手写自己的MyBatis框架-MapperProxy的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手写自己的MyBatis框架-Confi
- 下一篇: 手写自己的MyBatis框架-Execu