您的位置:首页 > 其它

MyBatis源码分析

2015-06-19 12:11 363 查看
今天,打算来写篇MyBatis的源码分析,也是这些天看MyBatis源码的总结吧。可能写的不是很好,但我觉得应该也能看下去,也能知道MyBatis的流程是怎么走的。

这里的图片上传了之后不能单独点开看,字体小看不清可以按住ctrl键然后滚动鼠标的滚扭可以调节页面的大小,放大点就能看清了…这里的不方便就只能将就一下啦…

好的,开始吧…

首先用debug模式运行一个项目,当然这个项目用的MyBatis,然后在controller里面设置一个断点



然后在浏览器运行进入这个方法里面进入debug窗口



在右上角的debug窗口可以看到一个MapperProxy.invoke方法点进去



这时你将看到MapperProxy类的源代码,如果你没有看不到那么你自己引入好了。在该类中你会看到一个invoke方法。



MapperProxy类实际上是所有映射接口的代理类,对接口的所有操作都会进入该类的invoke方法。

你可以在方法设置一个断点看看,它会断在这里停住,那么你就能看到它是如何执行了。

你会看到invoke方法会调用一个cachedMapperMethod方法,这个方法主要是根据method参数来获取MapperMethod对象。你可以在这个类的上面看到该类有一个methodCache的成员变量 为Map类型 ,key是Method,value是MapperMethod。cachedMapperMethod正是在这个Map集合里面根据Method缓存和获取MapperMethod对象的。最终invoke会调用MapperMethod对象的execute方法传入sqlsession参数和args参数数组来返回结果。

按住ctrl键点击execute方法进入MapperMethod类里面来看看这个方法是啥。



在MapperMethod类里面有个类型为SqlCommand的成员变量。这个sqlcommand封装了接口方法是什么类型的,也就是接口方法是执行update还是select还是delete操作的。



可以看到这里我调用的接口方法是select类型的。

然后一步一步执行下去会看到最终执行一个叫executeForMany的方法,还是继续传入sqlSession和args的参数。其实这里可以看出来前面的判断就是根据你接口方法的类型来执行不同的操作。executeForMany方法名可以看出是执行返回多个值的方法,下面还有executeForMap和executeOne的方法,不用我说也知道了吧。然后具体调用那个方法执行返回结果是根据method.returnsMany()方法或者是method.returnsMap()方法返回一个boolean值来确定的。



进入executeForMay方法来看看


这里定义了一个List类型的返回值result;然后调用sqlSession.< E>selectList方法来获取返回值.可以把鼠标放在SqlSession上面按ctrl+t,你会看到它的是一个接口和下面的实现类,实际这里的sqlSession对象是SqlSessionTemplate类



进入SqlSessionTemplate的selectList方法



我们可以看到返回的是sqlSessionProxy对象的selectList方法的返回值,我们来看看这个变量到底是哈。





从这里可以看出它是一个SqlSession接口接收的是一个代理类,下面看看这个代理类哈样



可以看出在这个invoke方法里面通过getSqlSession方法获取了一个SqlSession的对象

我们点进这个方法最终会看到如下这行代码:



sessionFactory是个SqlSessionFactory接口对象同样按ctrl+t来看,它有两个实现类



这里的SqlSessionFactor实际上是DefaultSqlSessionFactory对象,也就是说这里调用的是DefaultSqlSessionFactory对象的openSession方法,我们来看看这个方法



接下来进入openSessionFromDataSouce方法看看



可以看出它最终返回的是DefaultSqlSession对象…..

天呐..发现有点细…没关系,后面会总结的。

接下来回到SqlSessionTemplate类里面的代理类来看



我们知道这里的SqlSession实际对象是DefaultSqlSession了,也就是说我们调用的SqlSessionTemplate的方法最终都会调用DefaultSqlSession对应的方法进行执行。

如下:



咯~这就是DefaultSqlSession的selectList方法

该方法里获取了一个MapperStatement对象,MapperStatemnt封装了相关的映射信息和二级缓存的数据。

我们可以看到最终调用的是Executor对象的query方法,这里实际调用的是Executor的实现类CachingExecutor对象的query方法。

我们来看看



这个query方法里面有个Cache对象,该对象用于二级缓存,也就是说在这个方法里面先去查找Cache里面有没有对应的数据,有则返回,没有就去数据库中查找出来,然后存在Cache里面并且返回。有必要说一下,二级缓存是根据Sql语句来做为key的value是数据库中查出来的数据。

如果你没有配置二级缓存,这里会直接跳过这个if块,直接从数据库中查数据。

至此,大概的一个流程就是这样的…可把我累死了…

肯定有讲的不是很详细的地方,可能你也没看懂,没搞明白,没关系,可以自己去实际的看下源码,打开debug一步一步走,我想想你能搞明白的。还是得自己去实践…

总结:首先MyBatis会为所有的映射接口定义一个MapperProxy代理类,每次调用接口的方法实际调用的MapperProxy的invoke方法,MapperProxy根据Method来获取MapperMethod,MapperMethod根据SqlCommand来获取具体的方法类型来调用SqlSession对象的方法来获取数据。如果配置了二级缓存会先在二级缓存中查找数据,有则返回数据,没有则去数据库中查找返回。

有谁玩海岛奇兵的,可以加我战队:壹號 。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: