Mybatis源码阅读之七——门面模式以及bind模块

【系列目录】
Mybatis源码阅读之一——工厂模式与SqlSessionFactory

Mybatis源码阅读之二——模板方法模式与Executor

Mybatis源码阅读之三——JDBC解析与Mybatis封装

Mybatis源码阅读之四——装饰器模式与Mybatis中的各种Cache
Mybatis源码阅读之六——数据库连接池实现与hikariCP简析

【本文目录】

门面模式

什么是门面模式?

门面模式,又称外观模式,该模式提供一组统一的接口,让子系统更加易用。

门面模式用类图不好表示,一个大致流程图如下:

当一个外部调用到来时,如果调用的时方法A,那么将被Facade转发给A类去执行;如果是方法B/C则会分别转发给B/C类去执行。

由此可以看出,门面模式实际上使用一个门面类统合了琐碎的子类,让外部调用的使用方不需要再认知底层有这些ABC类,只需要与门面类打交道,实现了很好的解耦。

从上面的概念中,我们会发现,这个模式其实在我们不知不觉中经常会使用。

对于Java Web开发者来说,一些简单的domain是从低向上,从mapper–service–controller去设计,比如domain是商品,那么就是mapper<商品>–service<商品>–controller<商品>。
但是也会有很多复杂场景是从上向下的,典型的比如LoginController,我们可以将登陆/登出/当前权限获取/当前用户获取等都放在这个里面,进行一个统一管理,而具体方法的实现则可能是转发到了各个不同的Service中去。

SqlSession中的门面模式

回顾我们之前在Mybatis源码阅读之一——工厂模式与SqlSessionFactory中介绍的SqlSession,这就是一个典型的门面模式的实现。
其中CRUD内部是对Executor的转发,而getMapper/getConfiguration则是configuration的转发。

bind模块

包结构

binding包下的类虽然不多,却是核心逻辑的一部分。

  • MapperRegistry : Mapper的主要管理者,上述sqlSession的getMapper方法,最终就是转发到了这里。
  • MapperProxy : 我们业务mapper的xml生成的代理对象,(后面与代理模式一起分享)
  • MapperMethod : 对mapper方法级别的封装。

源码

回顾我们第一章的demo(下图),其中

这个demo中关于bing的部分,分两步来看:

  • 如图1,环境加载过程中的binding mapper相关逻辑。
  • 如图2,业务系统获取bind Mapper的过程。

Binging Mapper

  • SqlSessionFactoryBuilder.build

  • SqlSessionFactory.build(parser.parse())
    这里分两步看,一个是build让SqlSessionFactory持有了configuration对象。另一个则是对继续对document的解析(不了解document的可以看Mybatis源码阅读之五——Java的XML解析)。

  • XMLConfigBuilder.parse()

  • XMLConfigBuilder.parseConfiguration,这里我们只关注对mapper的处理逻辑。

  • 重要XMLConfigBuilder.mapperElement()
    先来看一个mybatis-config.xml中配置mapper的两种方式,一个是mapper标签配置到类,另一种是package标签配置到包。

    回到代码:

    • 第一步,对mappers下的标签循环处理。
    • 第二步,判断当前是package标签,是的话addMappers,这里稍后展开。
    • 第三步,如果不是package,那就是mapper标签。mapper中也分三种case,第一种是使用resource属性,此方式可以加载本地任意位置的xml文件
    • 第四步,接第三步,使用url属性,此方式可以加载本地/网络任意url的文件,第三四补都是直接拿到了xml资源文件,故而此处是直接进行了xml文件解析。
    • 第五步,接第三步,使用class属性,此方式指定的是Mapper类,同时对应的xml必须同名,此处同package方式类似逻辑,不是解析xml资源,而是调用configuration进行addMapper。
  • configuration.addMappers,如图,此时转发给了binding包下的MapperRegistry,MapperRegistry是在Configuration实例化时饿汉式单例加载的。

  • MapperRegistry.addMappers

  • MapperRegistry.addMapper

  • MapperAnnotationBuilder.parse

  • 值得一提,parseCache方法解析了一个注解,CacheNamespace,使用此注解也可以代替在xml中配置的方式来指定此Mapper使用二级缓存,源码与案例如下:
    此处可以使用指定的缓存,如果我们有LFU或者其他类型的缓存需求,可以自定义实现。

  • 回到MapperAnnotationBuilder.loadXmlResource(),此处就会将package方式与class方式加载的mapper对应的xml资源加载,而加载的文件名就是Mapper的文件名。

getMapper流程

现在Mappers都已经被Mybatis管理起来了,存放在MapperRegistry.knownMappers中。

回顾demo,getMapper时:

  • SqlSession.getMapper
  • Configuration.getMapper
  • MapperRegistry.getMapper
    这里发现对于每一个sqlSession来说会生成一个Mapper代理,不是我们平常理解的一个Mapper全局只有一个Mapper代理,这种设计直接将Mapper代理与SqlSession绑定在了一起。
  • MapperProxy.invoke
    这里很值得一提,具体的方法执行器有两个,DefaultMethodInvoker用于处理接口中的default方法,PlainMethodInvoker用于处理真正的xmlMapper方法(即sql)

  • DefaultMethodInvoker.invoke
    直接使用了jdk反射提供的MethodHandle来执行defaulr方法。
  • PlainMethodInvoker.invoke()
    这里才是拿到sql,真正去执行的地方。

关于代理模式,我们放在下次与Mybatis插件的实现一起解读。

总结

本文我们介绍了门面模式以及Mybatis中的应用,了解了一个Mapper以及他的xml资源文件何时/如何被加载,也了解了getMapper的简单过程。
额外的,还有配置mapper时,四种配置方式,package,resource,url,class。
以及了解二级缓存CacheNamespace。


欢迎关注微信公众号 【JAVA技术分享官】,公众号首发,持续输出原创高质量JAVA开发者知识点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值