Mybatis接口Mapper内的方法为啥不能重载吗?
動態代理的功能:通過攔截器方法回調,對目標target方法進行增強。
言外之意就是為了增強目標target方法。上面這句話沒錯,但也不要認為它就是真理,殊不知,動態代理還有投鞭斷流的霸權,連目標target都不要的科幻模式。
注:本文默認認為,讀者對動態代理的原理是理解的,如果不明白target的含義,難以看懂本篇文章,建議先理解動態代理。
1. 自定義JDK動態代理之投鞭斷流實現自動映射器Mapper
首先定義一個pojo。
public?class?User?{private?Integer?id;private?String?name;private?int?age;public?User(Integer?id,?String?name,?int?age)?{this.id?=?id;this.name?=?name;this.age?=?age;}//?getter?setter }再定義一個接口UserMapper.java。
public?interface?UserMapper?{public?User?getUserById(Integer?id);?? }接下來我們看看如何使用動態代理之投鞭斷流,實現實例化接口并調用接口方法返回數據的。
自定義一個InvocationHandler。
import?java.lang.reflect.InvocationHandler; import?java.lang.reflect.Method; import?java.lang.reflect.Proxy;public?class?MapperProxy?implements?InvocationHandler?{@SuppressWarnings("unchecked")public?<T>?T?newInstance(Class<T>?clz)?{return?(T)?Proxy.newProxyInstance(clz.getClassLoader(),?new?Class[]?{?clz?},?this);}@Overridepublic?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{if?(Object.class.equals(method.getDeclaringClass()))?{try?{//?諸如hashCode()、toString()、equals()等方法,將target指向當前對象thisreturn?method.invoke(this,?args);}?catch?(Throwable?t)?{}}//?投鞭斷流return?new?User((Integer)?args[0],?"zhangsan",?18);} }上面代碼中的target,在執行Object.java內的方法時,target被指向了this,target已經變成了傀儡、象征、占位符。在投鞭斷流式的攔截時,已經沒有了target。
寫一個測試代碼:
public?static?void?main(String[]?args)?{MapperProxy?proxy?=?new?MapperProxy();UserMapper?mapper?=?proxy.newInstance(UserMapper.class);User?user?=?mapper.getUserById(1001);System.out.println("ID:"?+?user.getId());System.out.println("Name:"?+?user.getName());System.out.println("Age:"?+?user.getAge());System.out.println(mapper.toString()); }output:
ID:1001 Name:zhangsan Age:18 x.y.MapperProxy@6bc7c054這便是Mybatis自動映射器Mapper的底層實現原理。
可能有讀者不禁要問:你怎么把代碼寫的像初學者寫的一樣?沒有結構,且缺乏美感。
必須聲明,作為一名經驗老道的高手,能把程序寫的像初學者寫的一樣,那必定是高手中的高手。這樣可以讓初學者感覺到親切,舒服,符合自己的Style,讓他們或她們,感覺到大牛寫的代碼也不過如此,自己甚至寫的比這些大牛寫的還要好,從此自信滿滿,熱情高漲,認為與大牛之間的差距,僅剩下三分鐘。
2. Mybatis自動映射器Mapper的源碼分析
首先編寫一個測試類:
public?static?void?main(String[]?args)?{SqlSession?sqlSession?=?MybatisSqlSessionFactory.openSession();try?{StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);List<Student>?students?=?studentMapper.findAllStudents();for?(Student?student?:?students)?{System.out.println(student);}}?finally?{sqlSession.close();}}Mapper長這個樣子:
public?interface?StudentMapper?{List<Student>?findAllStudents();Student?findStudentById(Integer?id);void?insertStudent(Student?student); }org.apache.ibatis.binding.MapperProxy.java部分源碼。
public?class?MapperProxy<T>?implements?InvocationHandler,?Serializable?{private?static?final?long?serialVersionUID?=?-6424540398559729838L;private?final?SqlSession?sqlSession;private?final?Class<T>?mapperInterface;private?final?Map<Method,?MapperMethod>?methodCache;public?MapperProxy(SqlSession?sqlSession,?Class<T>?mapperInterface,?Map<Method,?MapperMethod>?methodCache)?{this.sqlSession?=?sqlSession;this.mapperInterface?=?mapperInterface;this.methodCache?=?methodCache;}@Overridepublic?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{if?(Object.class.equals(method.getDeclaringClass()))?{try?{return?method.invoke(this,?args);}?catch?(Throwable?t)?{throw?ExceptionUtil.unwrapThrowable(t);}}//?投鞭斷流final?MapperMethod?mapperMethod?=?cachedMapperMethod(method);return?mapperMethod.execute(sqlSession,?args);}//?...org.apache.ibatis.binding.MapperProxyFactory.java部分源碼。
public?class?MapperProxyFactory<T>?{private?final?Class<T>?mapperInterface;@SuppressWarnings("unchecked")protected?T?newInstance(MapperProxy<T>?mapperProxy)?{return?(T)?Proxy.newProxyInstance(mapperInterface.getClassLoader(),?new?Class[]?{?mapperInterface?},?mapperProxy);}這便是Mybatis使用動態代理之投鞭斷流。
3. 接口Mapper內的方法能重載(overLoad)嗎?(重要)
類似下面:
public?User?getUserById(Integer?id); public?User?getUserById(Integer?id,?String?name);Answer:不能。
原因:在投鞭斷流時,Mybatis使用package+Mapper+method全限名作為key,去xml內尋找唯一sql來執行的。類似:key=x.y.UserMapper.getUserById,那么,重載方法時將導致矛盾。對于Mapper接口,Mybatis禁止方法重載(overLoad)。
最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,筆者這幾年及春招的總結,github 1.4k star,拿去不謝!下載方式1.?首先掃描下方二維碼 2.?后臺回復「Java面試」即可獲取總結
以上是生活随笔為你收集整理的Mybatis接口Mapper内的方法为啥不能重载吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 遇到上亿(MySQL)大表的优化....
- 下一篇: 为什么我不建议你用去 “ ! = nul