程序员高级码农II 发表于 2020-12-31 07:29:00

通用源码阅读指导mybatis源码详解:type包

type包

type包中的类有 55个之多。在碰到这种繁杂的情况时,肯定要留意归类总结。
归类总结是源码阅读中非常好的办法。每每越是大量的类,越是大量的方法,越有规律举行分类。这些本来繁杂的类和方法经过分类后,可能会变得很有条理。
经过梳理后,我们把 type包内的类分为以下六组。
· 类型处理惩罚器:1个接口、1个基础实现类、1个辅助类、43个实现类。
-TypeHandler:类型处理惩罚器接口;
-BaseTypeHandler:类型处理惩罚器的基础实现;
-TypeReference:类型参考器;
-*TypeHandler:43个类型处理惩罚器。
· 类型注册表:3个。
-SimpleTypeRegistry:根本类型注册表,内部使用 Set 维护了所有 Java 根本数据类型的集合;
-TypeAliasRegistry:类型别名注册表,内部使用 HashMap维护了所有类型的别名和类型的映射关系;
-TypeHandlerRegistry:类型处理惩罚器注册表,内部维护了所有类型与对应类型处理惩罚器的映射关系。
· 注解类:3个。
-Alias:使用该注解可以给类设置别名,设置后,别名和类型的映射关系便存入TypeAliasRegistry中;
-MappedJdbcTypes:有时我们想使用自己的处理惩罚器来处理惩罚某些 JDBC 类型,只需创建 BaseTypeHandler 的子类,然后在上面加上该注解,声明它要处理惩罚的JDBC类型即可;
-MappedTypes:有时我们想使用自己的处理惩罚器来处理惩罚某些Java类型,只需创建BaseTypeHandler的子类,然后在上面加上该注解,声明它要处理惩罚的 Java类型即可。
· 异常类:1个。
-TypeException:表现与类型处理惩罚相干的异常。
· 工具类:1个。
-ByteArrayUtils:提供数组转化的工具方法。
· 枚举类:1个。
-JdbcType:在 Enum中定义了所有的 JDBC类型,类型来源于 java.sql.Types。
以上类中,注解类、异常类、工具类、枚举类都非常简朴,不再单独先容。下面将重点先容类型处理惩罚器和类型注册表。
模板模式

说起模板大家应该都很熟悉。一样平常情况下,模板中规定了大体的框架,只留下一些细节供使用者来修改和完善。使用同一模板做出的差别产品都具有一致的框架。设计模式中的模板模式与上述模板的概念相同。在模板模式中,需要使用一个抽象类定义一套操作的整体步骤(即模板),而抽象类的子类则完成每个步骤的详细实现。这样,抽象类的差别子类遵循了同样的一套模板。
比方,我们定义一套扫除卫生的模板,如代码8-1 所示。它为所有的扫除卫生工作定义了四个大的步骤:准备(prepare)、实施(implement)、善后(windup)和汇报(report)。
【代码8-1】
https://p1.pstatp.com/large/pgc-image/7e813ea5806a48c39c6711a48f342e4f
这样,就可以基于该模板完成一些详细的扫除卫生工作。比方,代码8-2 和代码8-3分别给出了擦玻璃和擦黑板的实现。
【代码8-2】
https://p1.pstatp.com/large/pgc-image/09fcad27fc414ed4b17aa974fce3c49d
https://p1.pstatp.com/large/pgc-image/1240de66a3d9477dade96033756d55b9
【代码8-3】
https://p3.pstatp.com/large/pgc-image/8bfa3e910501483f8580463c6efd0e2f
可以看到,虽然详细的举动差别,但是 WipeGlass和 WipeBlackboard两者遵循的模板是一样的,都是由 Cleaning类给定的。这就是模板模式的作用,即确定了一套操作的框架,而子类只需在此框架的基础上定义详细的实现即可。
类型处理惩罚器

类型处理惩罚器的基类与实现类
作为一个 ORM框架,处理惩罚 Java对象和数据库关系之间的映射是 MyBatis工作中的重要部分。然而在 Java中存在 Integer、String、Data等各种类型的数据,在数据库中也存在varchar、longvarchar、tinyint等各种类型的数据。差别类型的字段所需的读、写方法各不相同,因此需要对差别类型的字段接纳相应的处理惩罚方式。
比方,User中有如代码8-4所示的几个属性。
【代码8-4】
https://p9.pstatp.com/large/pgc-image/2ebee3c533894cc193a7cdc6be4c793a
在对 User对象的属性举行读取和赋值时,需要用 Integer的相干处理惩罚方式来操作 id、sex属性,而要用 String的相干处理惩罚方式来操作name、schoolName属性。
在 type包中,将每种类型对应的处理惩罚方式封装在了对应的类型处理惩罚器 TypeHandler中。比方,IntegerTypeHandler负责完成对 Integer类型的处理惩罚。
type 包共有 43 个类型处理惩罚器,这些类型处理惩罚器的名称也均以“TypeHandler”结尾。而 TypeHandler和 BaseTypeHandler则分别是类型处理惩罚器接口和类型处理惩罚器基类。
图8-1展示了type包中类型处理惩罚器相干的类图。
https://p9.pstatp.com/large/pgc-image/deb980bc06654834ab33935018fe1fc2图8-1 类型处理惩罚器类图
TypeHandler<T>是一个接口,其中定义了举行数据处理惩罚操作的几个抽象方法。而BaseTypeHandler<T>继承了 TypeHandler<T>接口,并实现了 TypeHandler<T>中的接口。
在类型处理惩罚器相干类的设计中接纳了模板模式,BaseTypeHandler<T>作为所有类型处理惩罚器的基类,定义了模板的框架。而在各个详细的实现类中,则实现了详细的细节。
以代码8-5展示的 BaseTypeHandler中 getResult(ResultSet,String)方法为例,该方法完成了异常处理惩罚等同一的工作,而与详细类型相干的 getNullableResult(ResultSet,String)操作则通过抽象方法交给详细的类型处理惩罚器实现。这就是典型的模板模式。
【代码8-5】
https://p3.pstatp.com/large/pgc-image/f9607662cff24d01b7def553fb698e0b
BaseTypeHandler<T>交给详细的类型处理惩罚器实现的抽象方法一共只有四个。在每个类型处理惩罚器都需要实现这四个方法。· void setNonNullParameter(PreparedStatement,int,T,JdbcType):向 PreparedStatement对象中的指定变量位置写入一个不为null的值;
· T getNullableResult(ResultSet,String):从 ResultSet中按照字段名读出一个可能为null的数据;
· T getNullableResult(ResultSet,int):从 ResultSet 中按照字段编号读出一个可能为null的数据;
· T getNullableResult(CallableStatement,int):从 CallableStatement中按照字段编号读出一个可能为 null的数据。
由于上面的抽象方法跟详细的类型相干,因此存在泛型参数 T。在每种类型处理惩罚器中,都给出了泛型参数的值。以 IntegerTypeHandler为例,它设置泛型参数值为 Integer。IntegerTypeHandler类的源码如代码8-6所示。
【代码8-6】
https://p3.pstatp.com/large/pgc-image/60a78311e3f648449dddceafebaf8dac
代码8-6中,IntegerTypeHandler处理惩罚的类型是 Integer,这表明其 getNullableResult方法给出的就是一个 Integer结果。
TypeReference类
43个类型处理惩罚器可以处理惩罚差别 Java类型的数据,而这些类型处理惩罚器都是 TypeHandler接口的子类,因此可以都作为 TypeHandler来使用。
那会不会碰到一个问题,当 MyBatis取到某一个 TypeHandler时,却不知道它到底是用来处理惩罚哪一种 Java类型的处理惩罚器?
为了办理这一问题,MyBatis 定义了一个 TypeReference 类。它能够判断出一个TypeHandler用来处理惩罚的目标类型。而它判断的方法也很简朴:取出 TypeHandler实现类中的泛型参数 T的类型,这个值的类型也便是该 TypeHandler能处理惩罚的目标类型。该功能由getSuperclassTypeParameter方法实现,该方法能将找出的目标类型存入类中的 rawType属性。getSuperclassTypeParameter方法带解释的源码如代码8-7所示。
【代码8-7】
https://p1.pstatp.com/large/pgc-image/112971e9b9f14e6a8e40a492163a320e
TypeReference 类是 BaseTypeHandler 的父类,因此所有的类型处理惩罚器都继承了TypeReference 的功能。这意味着对任何一个类型处理惩罚器调用 getSuperclassTypeParameter方法,都可以得到该处理惩罚器用来处理惩罚的目标类型。
类型注册表

定义了大量的类型处理惩罚器之后,MyBatis 还需要在碰到某种类型的数据时,快速找到与数据的类型对应的类型处理惩罚器。这个过程就需要各种类型注册表的帮助。
type 包中的类型注册表有三个:SimpleTypeRegistry、TypeAliasRegistry 和TypeHandlerRegistry。
SimpleTypeRegistry 是一个非常简朴的注册表,其内部使用一个SIMPLE_TYPE_SET变量维护所有 Java根本类型。SIMPLE_TYPE_SET中的赋值是在 static代码块中举行的,如代码8-8所示。这说明在 SimpleTypeRegistry初始化结束后,就已经将所有的 Java根本类型维护到了 SIMPLE_TYPE_SET中。
【代码8-8】
https://p1.pstatp.com/large/pgc-image/5b042487352c4d74ad3ad49a8d68915b
TypeAliasRegistry是一个类型别名注册表,其内部使用 typeAliases变量维护类型的别名与类型的对应关系。有了这个注册表,我们就可以在很多场合使用类型的别名来指代详细的类型。TypeHandlerRegistry 是这三个注册表中最为核心的一个,数据类型和相干处理惩罚器的对应关系就是由它维护的。
在先容它之前,我们先先容 Java数据类型和 JDBC数据类型。假设某个对象中存在一个“String name”属性,则 name属性在 Java中的数据类型是String。
然而它在数据库中可能是 char、varchar,也可能是 tinytext、text 等多种类型。因此,Java数据类型和 JDBC数据类型并不是一对一的关系,而是一对多的关系。了解到这一点之后,我们在代码8-9中直接给出 TypeHandlerRegistry类的带解释的属性。
【代码8-9】
https://p3.pstatp.com/large/pgc-image/cac7fd5a8f564a358ab03dfd371f5f84
了解了 TypeHandlerRegistry的属性后,也可以猜测出如何才能拿到一个类型的类型处理惩罚器,实际就是一个两次映射的过程。
· 根据传入的 Java 类型,调用 getJdbcHandlerMap 子方法找寻对应的jdbcTypeHandlerMap后返回。· 基于 jdbcTypeHandlerMap,根据 JDBC类型找到对应的 TypeHandler。
比方,在给定 Java类型是 String,而 JDBC类型是 varchar后,就能唯一确定一个类型处理惩罚器。getTypeHandler 方法完成的就是这一过程,该方法带解释的源码如代码8-10所示。
【代码8-10】
https://p1.pstatp.com/large/pgc-image/3b1a9edb5c0c46d1bd9c739298bd80d1
SimpleTypeRegistry、TypeAliasRegistry、TypeHandlerRegistry这三个类型注册表的存在,使 MyBatis 不仅可以根据类型找寻其类型处理惩罚器,而且还可以根据类型别名找寻对应的类型处理惩罚器。
本文给大家解说的内容是通用源码阅读指导mybatis源码详解: type包


[*]下篇文章给大家解说的是通用源码阅读指导mybatis源码详解: io包;
[*]觉得文章不错的朋友可以转发此文关注小编;
[*]感谢大家的支持

吴凡86 发表于 2020-12-31 10:42:53

转发了
页: [1]
查看完整版本: 通用源码阅读指导mybatis源码详解:type包