mybatis源码详解设置解析包源码阅读:builder包
builder包builder包是一个按照范例划分出来的包,包中存在很多的建造者类。在这一章的源码阅读中,我们将对这些建造者类及其相干的辅助类进行相识。
虽然 builder包是一个按照范例方式划分的包,但是在该包中也完成了以下两个比较完整的功能。
· 一是剖析 XML设置文件和映射文件,这部分功能在 xml子包中;
· 二是剖析注解形式的 Mapper声明,这部分功能在 annotation子包中。
通过该章我们也会相识以上两个功能的实现原理。
建造者模式
在软件开发过程中,常常需要新建对象并给对象的属性赋值。当对象的属性比较多时,创建对象的过程会变得比较烦琐。
例如,某个平台需要在开学季给Sunny School和Garden School两所学校的新同砚注册账号。Sunny School是一所小学,新同砚年龄大多为 7岁;Garden School是一所中学,新同砚年龄大多为 13岁。在注册账号的过程中,如果同砚没有电子邮箱的话还要为其注册电子邮箱。
先建造空对象,然后再不断调用 set 方法为对象属性赋值是一种常见的建造对象的方式,如代码14-1所示。这种方式需要相识对象的全部属性细节,是与对象的属性耦合的,而且这个过程中可能会导致属性的遗忘。
【代码14-1】
https://p1.pstatp.com/large/pgc-image/dacd55815bde4920873a2e18ddd91f96
使用具有多个输入参数的构造方法直接建造对象也是一种常见的建造对象的方式,如代码14-2所示。这种环境下,为了能适应多种输入参数组合,通常需要重载大量的构造方法。
【代码14-2】
https://p9.pstatp.com/large/pgc-image/efa178ec4668467ba35df232f10fc834
建造者模式给我们提供了另一种建造对象的思路。使用建造者模式,对象的建造细节均交给建造者来完成,调用者只需掌控总体流程即可,而不需要相识被建造对象的细节。
例如,编写一个 UserBuilder接口作为建造 User对象的接口,如代码14-3所示。
【代码14-3】
https://p1.pstatp.com/large/pgc-image/ad6a016bd4c2449db6789ef32fc204dc
https://p1.pstatp.com/large/pgc-image/35ba2c01bca7457f86eb504ab5ad8c3f
然后继续 UserBuilder 接口编写一个 SunnySchoolUserBuilder类,它用来建造 Sunny School的用户,如代码14-4所示。
【代码14-4】
https://p3.pstatp.com/large/pgc-image/059ea56e83284037b68b739de6eca907
https://p1.pstatp.com/large/pgc-image/8d15cdf293f845178c8f9ff7e7542ca6
这样一来,我们可以通过代码14-5所示的方式来机动地建造对象。
【代码14-5】
https://p3.pstatp.com/large/pgc-image/53e967a0617544bba77d464236fd2c0a
基于建造者创建对象时,有以下几个长处。
· 使用建造者时十分机动,可以一次也可以分多次设置被建造对象的属性;
· 调用者只需调用建造者的重要流程而不需要关系建造对象的细节;
· 可以很方便地修改建造者的行为,从而建造出不同的对象。
图14-1给出了建造者模式的类图。
https://p1.pstatp.com/large/pgc-image/6869588ffe674ae5adc1d43f8fe325ae图14-1 建造者模式的类图
在学习了建造者模式后,可以为属性较多的类创建建造者类。建造者类一样平常包含两类方法:
· 一类是属性设置方法。这类方法一样平常有多个,可以担当不同范例的参数来设置建造者的属性。
· 一类是目标对象天生方法。该类方法一样平常只有一个,即根据如今建造者中的属性创建出一个目标对象。
在需要创建复杂的对象时,建造者模式的上风将会体现得更为显着。因此,建造者模式在一些大型的系统中非常常见。
建造者基类与工具类
builder包中的 BaseBuilder类是全部建造者的基类,图14-2所示是它与子类的类图。
https://p1.pstatp.com/large/pgc-image/e5449ec541514f55a41a67f6ff2645bc图14-2 BaseBuilder类及其子类的类图
BaseBuilder类虽然被声明成一个抽象类,但是本身不含有任何的抽象方法,因此它的子类无须实现它的任何方法。BaseBuilder类更像一个工具类,为继续它的建造者类提供了众多实用的工具方法。当然,也确实有很多建造者类不需要 BaseBuilder提供的工具方法,因此没有继续 BaseBuilder,这些类有 MapperAnnotationBuilder、SelectBuilder等。
BaseBuilder类提供的工具方法大致分为以下几类。
·*ValueOf:范例转化函数,负责将输入参数转换为指定的范例,并支持默认值设置;
· resolve*:字符串转枚举范例函数,根据字符串找出指定的枚举范例并返回;
· createInstance:根据范例别名创建范例实例;· resolveTypeHandler:根据范例处理器别名返回范例处理器实例。
在BaseBuilder类的子类中,MapperBuilderAssistant类最为特殊,因为它本身不是建造者类而是一个建造者辅助类。它继续 BaseBuilder 类的缘故起因仅仅是因为要使用 BaseBuilder类中的方法。
MyBatis 映射文件中的设置项非常多,包括命名空间、缓存共享、结果映射等。最终这些设置将剖析天生不同的类,而 MapperBuilderAssistant类是这些剖析类的辅助类。
MapperBuilderAssistant 类提供了很多辅助方法,如 Mapper 命名空间的设置、缓存的创建、鉴别器的创建等。例如,代码14-6展示了其中的缓存创建方法。
【代码14-6】
https://p3.pstatp.com/large/pgc-image/8b7bcdc76e254190a090b92bded4da35
https://p1.pstatp.com/large/pgc-image/1a2646cc6e954fb99cc5616b514f0e7a
MapperBuilderAssistant 类中还有很多其他实用的方法,我们会在用到它们时再具体介绍。
通过 BaseBuilder 类和 MapperBuilderAssistant 类我们知道,建造者类不一定继续了BaseBuilder,而继续了 BaseBuilder的类也不一定是建造者类。
SqlSourceBuilder类与StaticSqlSource类
SqlSourceBuilder 是一个建造者类,但它的名字有些歧义,它不能用来创建全部的SqlSource 对象(SqlSource 是一个接口,有四种实现),而是只能通过 parse 方法生产出StaticSqlSource这一种对象。
确切地说,SqlSourceBuilder 类能够将 DynamicSqlSource 和 RawSqlSource 中的“#{}”符号更换掉,从而将它们转化为 StaticSqlSource,这一转化过程发生在代码14-7所示的 parse方法中。因此,把SqlSourceBuilder类称作一个剖析器或者转化器更符合。而究竟上,很多引用 SqlSourceBuilder对象的地方都将对象的变量名定为“sqlSourceParser”(在 DynamicSqlSource和 RawSqlSource类中都能找到这个变量)。
【代码14-7】
https://p3.pstatp.com/large/pgc-image/d51892501a114737be56e7899d117634
StaticSqlSource是 SqlSource的四个子类之一,它内部包含的 SQL语句中已经不存在“${}”和“#{}”这两种符号,而只有“?”,其属性的表明如代码14-8 所示。在 15.1.2节我们还会具体介绍它的来龙去脉。
【代码14-8】
https://p3.pstatp.com/large/pgc-image/ccd1861aa54c44498894a48327d22f64
StaticSqlSource 有一个非常重要的功能,那就是给出一个 BoundSql 对象。StaticSqlSource内 getBoundSql方法负责完成这项功能,如代码14-9所示。
【代码14-9】
https://p1.pstatp.com/large/pgc-image/4c079ee3d18b42ee862e279890e2028d
CacheRefResolver类和ResultMapResolver类
CacheRefResolver类和 ResultMapResolver类有几分相似之处,不但类名上相似,在结构和功能上也相似。它们都是某些类的剖析器类,属性中包含被剖析类的相干属性,同时还包含一个剖析器。这样,类中的剖析器就可以完成对被剖析类属性的剖析工作。
这些整合后的具有剖析功能的类在 MyBatis中有着规范的命名:如果被剖析对象名称为 A,则整合后的自剖析类叫作 AResolver。这样,在之后的分析中遇到这样命名的类,就可以直接分析它的组成和作用。这种命名方式和功能是相对通用的,但不是绝对的。例如,annotation子包中的 MethodResolver就符合这种模式,包含被剖析对象的属性息争析器;而ParamNameResolver 就不符合这种模式,因为它的剖析功能是自身通过方法实现的,不需要依赖其他的剖析器。
CacheRefResolver类
MyBatis支持多个 namespace之间共享缓存。如代码14-10所示,在“com.github.yeecode.mybatisdemo.dao.UserDao”的命名空间内我们通过<cache-ref>标签声明了另外一个命名空间“com.github.yeecode.mybatisdemo.dao.TaskDao”,那么前者会使用后者的缓存。更具体的介绍可以参考 19.8节。
【代码14-10】
https://p3.pstatp.com/large/pgc-image/b008fbf98bb34154bcb151f6da8b9da8
CacheRefResolver 类用来处理多个命名空间共享缓存的问题。它自身有两个属性,如代码14-11所示。这两个属性中,assistant是剖析器,cacheRefNamespace是被剖析对象。
【代码14-11】
https://p1.pstatp.com/large/pgc-image/ed095dbe9bfa4f9ca539d5c21058b188
借助于 MapperBuilderAssistant的 useCacheRef方法,CacheRefResolver类可以剖析缓存共享的问题。MapperBuilderAssistant的 useCacheRef方法如代码14-12所示。
【代码14-12】
https://p3.pstatp.com/large/pgc-image/94c050b16f4543c6891bd7ba48a9078f
https://p3.pstatp.com/large/pgc-image/073f16ccf7774522ab61e84786fb319a
ResultMapResolver类
MyBatis 的 resultMap 标签支持继续。如代码14-13 所示,“girlUserMap”通过设置“extends="userMap"”继续了“userMap”中设置的属性映射。
【代码14-13】
https://p1.pstatp.com/large/pgc-image/5e65807afc204ea0a35734f554ff6da6
resultMap 继续关系的剖析由 ResultMapResolver 类来完成。代码14-14 给出了ResultMapResolver类的属性,其中 assistant属性是剖析器,其他属性则是被剖析的属性。
【代码14-14】
https://p1.pstatp.com/large/pgc-image/2b830f168e7f41ac86485c9db139a669
https://p1.pstatp.com/large/pgc-image/a48623d2a8724f03a5047d9fea200289
借助于 MapperBuilderAssistant 的 addResultMap 方法,ResultMapResolver 完成了ResultMap 的继续关系剖析,最终给出一个剖析完继续关系之后的 ResultMap 对象。MapperBuilderAssistant的 addResultMap方法如代码14-15所示。
【代码14-15】
https://p1.pstatp.com/large/pgc-image/bfb6f5378bd7461f85064788516b7cea
https://p3.pstatp.com/large/pgc-image/bb99ebe157314c54a53fee0e88f05db3
本文给大家讲解的内容是通用源码阅读引导mybatis源码详解设置剖析包源码阅读:builder包
[*]下篇文章给大家讲解的是通用源码阅读引导mybatis源码详解设置剖析包源码阅读:builder包ParameterExpression类;
[*]觉得文章不错的朋侪可以转发此文关注小编;
[*]感谢大家的支持!
页:
[1]