MyBatis 源码分析 - 配置文件解析过程 (12)

上面代码中用于解析 XML 部分的代码比较简单,没什么需要特别说明的。除此之外,上面的代码中调用了4个不同的类型处理器注册方法。这些注册方法的逻辑不难理解,但是重载方法很多,上面调用的注册方法只是重载方法的一部分。由于重载太多且重载方法之间互相调用,导致这一块的代码有点凌乱。我一开始在整理这部分代码时,也很抓狂。后来没辙了,把重载方法的调用图画了出来,才理清了代码。一图胜千言,看图吧。

MyBatis 源码分析 - 配置文件解析过程

在上面的调用图中,每个蓝色背景框下都有一个标签。每个标签上面都已一个编号,这些编号与上面代码中的标签是一致的。这里我把蓝色背景框内的方法称为开始方法,红色背景框内的方法称为终点方法,白色背景框内的方法称为中间方法。下面我会分析从每个开始方法向下分析,为了避免冗余分析,我会按照③ → ② → ④ → ①的顺序进行分析。大家在阅读代码分析时,可以参照上面的图片,辅助理解。好了,下面开始进行分析。

2.8.1 register(Class, JdbcType, Class) 方法分析

当代码执行到此方法时,表示javaTypeClass != null && jdbcType != null条件成立,即使用者明确配置了javaType和jdbcType属性的值。那下面我们来看一下该方法的分析。

public void register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass) { // 调用终点方法 register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass)); } /** 类型处理器注册过程的终点 */ private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) { if (javaType != null) { // JdbcType 到 TypeHandler 的映射 Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType); if (map == null || map == NULL_TYPE_HANDLER_MAP) { map = new HashMap<JdbcType, TypeHandler<?>>(); // 存储 javaType 到 Map<JdbcType, TypeHandler> 的映射 TYPE_HANDLER_MAP.put(javaType, map); } map.put(jdbcType, handler); } // 存储所有的 TypeHandler ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler); }

上面的代码只有两层调用,比较简单。同时,所谓的注册过程也就是把类型和处理器进行映射而已,没什么特别之处。关于这个方法就先分析到这里,继续往下分析。下面的方法对应注册方法②。

2.8.2 register(Class, Class) 方法分析

当代码执行到此方法时,表示javaTypeClass != null && jdbcType == null条件成立,即使用者仅设置了javaType属性的值。下面我们来看一下该方法的分析。

public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) { // 调用中间方法 register(Type, TypeHandler) register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass)); } private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) { // 获取 @MappedJdbcTypes 注解 MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class); if (mappedJdbcTypes != null) { // 遍历 @MappedJdbcTypes 注解中配置的值 for (JdbcType handledJdbcType : mappedJdbcTypes.value()) { // 调用终点方法,参考上一小节的分析 register(javaType, handledJdbcType, typeHandler); } if (mappedJdbcTypes.includeNullJdbcType()) { // 调用终点方法,jdbcType = null register(javaType, null, typeHandler); } } else { // 调用终点方法,jdbcType = null register(javaType, null, typeHandler); } }

上面的代码包含三层调用,其中终点方法的逻辑上一节已经分析过,这里不再赘述。上面的逻辑也比较简单,主要做的事情是尝试从注解中获取JdbcType的值。这个方法就分析这么多,下面分析注册方法④。

2.8.3 register(Class) 方法分析

当代码执行到此方法时,表示javaTypeClass == null && jdbcType != null条件成立,即使用者未配置javaType和jdbcType属性的值。该方法的分析如下。

public void register(Class<?> typeHandlerClass) { boolean mappedTypeFound = false; // 获取 @MappedTypes 注解 MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class); if (mappedTypes != null) { // 遍历 @MappedTypes 注解中配置的值 for (Class<?> javaTypeClass : mappedTypes.value()) { // 调用注册方法 ② register(javaTypeClass, typeHandlerClass); mappedTypeFound = true; } } if (!mappedTypeFound) { // 调用中间方法 register(TypeHandler) register(getInstance(null, typeHandlerClass)); } } public <T> void register(TypeHandler<T> typeHandler) { boolean mappedTypeFound = false; // 获取 @MappedTypes 注解 MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class); if (mappedTypes != null) { for (Class<?> handledType : mappedTypes.value()) { // 调用中间方法 register(Type, TypeHandler) register(handledType, typeHandler); mappedTypeFound = true; } } // 自动发现映射类型 if (!mappedTypeFound && typeHandler instanceof TypeReference) { try { TypeReference<T> typeReference = (TypeReference<T>) typeHandler; // 获取参数模板中的参数类型,并调用中间方法 register(Type, TypeHandler) register(typeReference.getRawType(), typeHandler); mappedTypeFound = true; } catch (Throwable t) { } } if (!mappedTypeFound) { // 调用中间方法 register(Class, TypeHandler) register((Class<T>) null, typeHandler); } } public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) { // 调用中间方法 register(Type, TypeHandler) register((Type) javaType, typeHandler); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzyxw.html