# 问题
上一篇我们讲到,对于未知数据类型的解析,UnknownTypeHandler 把部分任务交给了 TypeHandlerRegistry ,甚至可能仅仅只丢了一个 javaType 过来就要求返回一个合适的解析器回去 。TypeHandlerRegistry 到底里面做了啥可以找到合适的解析器呢?
# 功能
从类的名字我们就知道这个类的功能大概就是个注册表,而且很可能是全局共用的,记录各种 javaType,jdbcType,TypeHandler 的映射关系。实际这个类的核心也就是维护了几个 map 。
# 核心字段
# JDBC_TYPE_HANDLER_MAP
|
|
这个很直观,就是注册 jdbcType 和解析器的对应关系。
# TYPE_HANDLER_MAP
|
|
书上原文是:“记录了 java 类型向指定的 JdbcType 转换时,需要使用的 TypeHandler 对象。例如:Java 类型中的 String 转换成数据库的 char 、varchar 等多种类型,所以存在一对多关系”。
Type 是 java.lang.reflect 包下的接口,Class 类实现了此接口。所以此 map 的 key 值是 javaType ,比如 String.class 。
# UNKNOWN_TYPE_HANDLER
就是上一篇文章学习过的 UnknownTypeHandler 的实例,主要用在 Object.class 和 JdbcType.OTHER 上。
# ALL_TYPE_HANDLERS_MAP
|
|
key 是解析器的 class ,value 是解析器自身。
记录了全部的解析器的类型及该类型相对应的 TypeHandler 对象。
# NULL_TYPE_HANDLER_MAP
仅仅是一个空 TypeHandler 集合的标识。因为 TYPE_HANDLER_MAP 是ConcurrentHashMap, 不能塞 null 值,因此在需要的地方以此空标识作为 value 替代null塞入。
# 注册
在构造方法中,就调用了大量的 register(…) 的方法,注册了很多映射关系。
register 有很多重载方法,除了简单的向 JDBC_TYPE_HANDLER_MAP 注册之外,全都最终指向了下面的重载方法。
|
|
方法并不复杂,我们只需要理解的是这里为两个 map 中都塞入了值,一个是 key 为 javaType 的 map , 也就是 String 与 char/varchar 的一对多的关系。另一个则是记录全部 handler 的map。
这里有一点需要特别留意的就是,比如 String 类,除了映射 char/varchar 之外,还映射 null ,对应的解析器也是 StringTypeHandler 。
|
|
# 查找 TypeHandler
终于到了查找 TypeHandler 的部分了,看了这么久,是不是差点晕得都忘了我们的这个注册表最核心的功能在这呢?
根据 jdbcType 和 typeHandler 的class 查找解析器的功能都很简单,就是上面的 JDBC_TYPE_HANDLER_MAP 和 ALL_TYPE_HANDLERS_MAP 中取值。
关键的在于根据 javaType 寻找解析器。而且我们的在上一篇也讲到了 PreparedStatement 在赋值的时候,我们没有提供 jdbcType ( null ), 仅仅只有 javaType 。
getTypeHandler 其实就是从 TYPE_HANDLER_MAP 取值.我们入参类型为 String 为例来看看其查找解析器的过程 。
|
|
# 总结
目前我们已经接触过了两种方式对明确指明的 javaType 的转换。主要可以分为两大类:
# ObjectTypeHandler
这个主要依靠 JDBC 底层的方法来查找合适的 javaType ,大量的 switch-case 语句。主要用在将返回值的封装到 JSONObject 中。
|
|
# TypeHandlerRegistry
注册表功能,将常规的数十种关系映射在初始化时就都注册好,也就是提前存入 map 中,需要的时候去 map 中取。
尤其是将 javaType 和 TypeHandler 关联起来,并对一些类型注册了默认的解析器,即 jdbcType 未指明时所要采用的解析器。
这个更多是用在 PreparedStatement 入参的赋值时。