书接上回,第二讲我们看了xml的解析过程,也看了生成的Configuration对象里面的东西,但是有一个东西是需要我这边着重讲解的。那就是mapperElement(root.evalNode("mappers"));今天我们就来看下这个Configuration是怎样把我们的Mapper搞进去的。
映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:
<!-- 使用相对于类路径的资源引用 --> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers>
<!-- 使用完全限定资源定位符(URL) --> <mappers> <mapper url="file:///var/mappers/AuthorMapper.xml"/> <mapper url="file:///var/mappers/BlogMapper.xml"/> <mapper url="file:///var/mappers/PostMapper.xml"/> </mappers>
<!-- 使用映射器接口实现类的完全限定类名 --> <mappers> <mapper class="org.mybatis.builder.AuthorMapper"/> <mapper class="org.mybatis.builder.BlogMapper"/> <mapper class="org.mybatis.builder.PostMapper"/> </mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 --> <mappers> <package name="org.mybatis.builder"/> </mappers>
这些配置会告诉 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件了,也就是接下来我们要讨论的。
我们看下mybatis源码是怎样找的
几个if分支,刚好对应这几种情况
我们看下这个addMapper
原来是把和些mapper放入到一个map里面了
这里有个问题哈,他这knownMappers是一个hashMap,而且是类的成员变量,这里会不会有并发问题了???
其实不会有,这个是启动注册的时候,肯定是主线程干的事,不会有问题。
此外,我们这里可以有一个小小的优化点,我们看下源码如果配置的是包扫描的源码:
其实就是for循环添加,如果为我们mapper接口有上千万个(当然有点困难哈),这样效率是不是有那么一丢丢的慢啊,我们这里有个解决方案。
1.把knownMappers改为ConcurrentHashMap,多线程并行流处理
类似这样的
list.stream().parallel().forEach()
记住多线程处理,不一定就比单线程快哦,他们都是有说法的,就是简单的处理数据的话,其实是有一个阈值的,你们可能不知道,给你看下Arrays里面人家算出来的阈值。可要瞪大眼睛哦,这个你们可能很多人都不知道哦
这个是Arrays里面的一个处理sort的方法,如果n小于2的13次方,或者是并行度为1,单线程处理,否则多线程处理。
哈哈,长知识了吧。
这边大家可以想一下,addMapper的时候,我的mapper都已经被解析了,
在添加mapper里面有这个方法,我们看一下
我们拿到我们这个mapper接口里面的所有方法,去遍历它,执行他的parseStatement
这个方法很多东西,其实总结下来就是 addMappedStatement,构建这个mappedStatement
这里面还有一个SqlSoruce我们看下有啥东西,
这些东西都是在这一步能够确定的,我们已经把配置文件里面的配置信息都拿到了,而且把我们的sql也解析出来了
下一步就是openSesson操作了
我们看下如何构建我们的SqlSession吧
我们看下这个执行器是如何构建的
我这代码都有注释,我就可以少逼逼一点,可以看到,这个地方用了两个设计模式,一个装饰者模式,一个拦截器模式
都说学习设计模式有啥用,今天就告诉你,源码是怎样用的。把这两个模式学习下,再结合源码分析下,就下播。
首先什么是装饰者模式
在不改变原有对象的基础之上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能)
适用场景:
- 扩展一个类的功能或者给一个类添加附加职责
- 给一个对象动态的添加功能,或动态撤销功能。
优点
- 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能。(继承在扩展功能是静态的,必须在编译时就确定好,而使用装饰者可以在运行时决定,装饰者也建立在继承的基础之上的)
- 通过使用不同装饰类以及这些类的排列组合,可以实现不同的效果。
- 符合开闭原则
缺点
- 会出现更多的代码,更多的类,增加程序的复杂性。
- 动态装饰时,多层装饰时会更复杂。(使用继承来拓展功能会增加类的数量,使用装饰者模式不会像继承那样增加那么多类的数量但是会增加对象的数量,当对象的数量增加到一定的级别时,无疑会大大增加我们代码调试的难度)
- 装饰者和代理模式
装饰者模式关注的是对象的动态添加功能。代理模式关注的是对对象的控制访问,对它的用户隐藏对象的具体信息
不想多逼逼,直接来一个案例,写下代码装饰者模式怎么用吧
案例:
首先假设一个应用场景吧假设我们现在在路边摊看到一个卖煎饼果子的,现在想买煎饼果子,煎饼果子一般的话都是可以加鸡蛋加香肠什么的,好那我们就来模拟一下加在煎饼果子上加东西的操作
此处的设计模式先放着,等下单独写一章关于mybatis的设计模式慢慢研究。