本篇内容介绍了“如何解决Mybatis导致的问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
背景
前段时间在我的技术群里,大家讨论起了为什么UserMapper.java是个接口,没有具体实现类,而我们可以直接调用其方法?
关于这个问题,我之前面试过一些人,很多人是这么回答的:
1.我领导叫我们使用Mybatis,大家都这么用就这么用了(没想过,反正就这么用)。
2.虽然我不知道具体是怎么实现的,但我觉得肯定是……(此处略去若干的漫天猜想),但是也不对啊,难道是……(再次略去若干似懂非懂)。
3.使用动态代理实现的(然后就没有下文了)。
对于上面的三种回答,前面两种我们就没必要往下聊了。
但是第三种回答,就有必要往下问:那你说说动态代理有哪些实现方式?Mybatis使用的是哪一种?
如果这个问题你还能回答上来,那么还会继续问:UserMapper.java中大方法能不能重载?
如果你能回答上面的问题,本文就没必要往下看了,已经不适合你了。
问题分析
先来看一张图,这图里的代码就是我们前面写的demo:
为什么一个接口就能和一个xml文件给绑定的呢?这就是今天我们要聊的话题。
可能很多小伙伴不熟悉ibatis,2010年之前,还没有Mybatis,之后ibatis便成了现在的Mybatis,如果有兴趣的朋友,可以看到Mybatis中的包目录。
这个包目录中就还是ibatis,并且ibatis的作者现在就在腾讯上班,开发英雄联盟LOL。
如果有腾讯的小伙伴可以打听打听哈,大佬就在身边。言归正传。
Mapper层在Mybatis中现在是接口形式就搞定了,而在ibatis时代还是必须要有实现类的,我记得2012年的时候,使用的就是ibatis,Dao(Mapper)必须要有实现类。
下面我们就来看看Mybatis中是怎么做的。
使用案例
继续使用我们上一节中的代码。
controller
service实现类中
打一个断点,然后使用debug模式启动项目。并访问:
http://localhost:9002/test
userMapper=org.apache.ibatis.binding.MapperProxy@6da21078
发现Mybatis给UserMapper.java生成了一个代理对象,并且从名字上可以看出是JDK动态代理。
关于动态代理请,这里我推荐我之前写过的一篇文章:
https://gitbook.cn/m/mazi/activity/5d44e35e4fbf44126135c292?sut=c93c00a03b4f11eba07ad99b4dfbdab0&utm_source=chatweixinshare
其实,又差不多回到了ibatis时代,只是Mybatis中是通过动态代理的方式生成的代理类不是我们开发的,而是通过JDK动态代理生成的代理类。
下面我们也使用JDK动态代理来模拟一把。
public class MapperProxy implements InvocationHandler { @SuppressWarnings("unchecked") public <T> T newInstance(Class<T> clz) { return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] { clz }, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { // 诸如hashCode()、toString()、equals()等方法,将target指向当前对象this return method.invoke(this, args); } catch (Throwable t) { } } // 投鞭断流 return new User((Integer) args[0], "田维常", 22); } }
再写一个测试类
import com.tian.mybatis.entity.User; import com.tian.mybatis.mapper.UserMapper; public class TestProxy { public static void main(String[] args) { MapperProxy proxy = new MapperProxy(); UserMapper mapper = proxy.newInstance(UserMapper.class); User user = mapper.selectById(999); System.out.println(user); System.out.println(mapper.toString()); } }
输出
User{id=999, userName='田维常', age=22, gender=null} com.tian.mybatis.proxy.MapperProxy@39a054a5
这便是Mybatis自动映射器Mapper的底层实现原理。
但是在Mybatis中,远远不是这么简单的,但是本质就是这样的。
下面我们就来大致分析一下Mybatis中的这个流程。
接口Mapper内的方法能重载吗?
类似下面:
public User getUserById(Integer id);
public User getUserById(Integer id, String name);
答案:不能
因为Mybatis中是使用package+Mapper+method全限名作为key,去xml内寻找唯一sql来执行的。
类似:key=com.tian.mybatis.UserMapper.getUserById,那么,重载方法时将导致矛盾。
对于Mapper接口,Mybatis禁止方法重载(overLoad) 。
在MapperMethod类的静态内部类中SqlCommand中有个resolveMappedStatement方法。
在Configuration中有个属性,就是项目启动的时候,会把Mapper.xml中信息解析到这个属性里,以我们指定的namespace+method作为key放到Map里面,后面我们调用Mapper接口动态类的某个方法时候再去map获取。
protected final Map<String, MappedStatement> mappedStatements
就是使用类的全路径名.方法作为key存放到Map中的。
“如何解决Mybatis导致的问题”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。