写点什么

聊聊 Mybatis 的类型转换注册类 TypeHandlerRegistry

作者:周杰伦本人
  • 2022-11-24
    山东
  • 本文字数:2250 字

    阅读完需:约 7 分钟

聊聊 Mybatis 的类型转换注册类 TypeHandlerRegistry

上篇文章中我们说到 TypeHandler 是进行类型转换的接口,它有针对不同的类型有很多实现类,TypeHandlerRegistry 来进行统一管理


Mybatis 初始化 TypeHandler 后,调用 TypeHandlerRegistry 的 register()方法进行注册,下面就看一下 register()

注册类型转换处理器

ypeHandlerRegistry 的 register()方法:


private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {        if (javaType != null) {             Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);            if (map == null || map == NULL_TYPE_HANDLER_MAP) {                map = new HashMap<>();            }            map.put(jdbcType, handler);            typeHandlerMap.put(javaType, map);        }        allTypeHandlersMap.put(handler.getClass(), handler);    }
复制代码


allTypeHandlersMap 中保存着所有 TypeHandler 类型和它对应的实例,除了这个 register()方法,还可以根据 @MappedJdbcTypes 和 @MappedTypes 注解获取数据,@MappedTypes 配置配置 TypeHandler 接口与 Java 类型的集合,@MappedJdbcTypes 配置 TypeHandler 接口与 Jdbc 类型的集合,TypeHandlerRegistry 的构造方法中调用了很多注册方法对不同 jdbc 类型选择不同 TypeHandler 的实例来进行注册


完成类型与 TypeHandler 实例的注册后,mybatis 会根据 java 类型和 jdbc 类型来查找对应的 TypeHandler 实例,调用方法是 TypeHandlerRegistry 的 getTypeHandler()方法:

获取类型处理器

TypeHandlerRegistry 的 getTypeHandler()方法:


private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {        if (ParamMap.class.equals(type)) {            return null;        }        Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);        TypeHandler<?> handler = null;        if (jdbcHandlerMap != null) {            handler = jdbcHandlerMap.get(jdbcType);            if (handler == null) {                handler = jdbcHandlerMap.get(null);            }            if (handler == null) {                handler = pickSoleHandler(jdbcHandlerMap);            }        }        // type drives generics here        return (TypeHandler<T>) handler;    }
复制代码


  1. 调用 getJdbcHandlerMap()方法根据 Java 类型查找对应的 TypeHandler 集合

  2. 如果不为空,根据 jdbcType 获取 TypeHandler 实例,如果找不到实例就使用 null 来获取 TypeHandler 的实例

  3. 如果 jdbcHandlerMap 只注册了一个 TypeHandler,就使用这个 TypeHandler 对应的实例


再看一下 getJdbcHandlerMap()方法:

获取 jdbc 类型对应的处理器

private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMap(Type type) {        Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(type);        if (NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap)) { // 检测是否为空集合标识            return null;        }        if (jdbcHandlerMap == null && type instanceof Class) {            Class<?> clazz = (Class<?>) type;            if (Enum.class.isAssignableFrom(clazz)) { // 针对枚举类型的处理                Class<?> enumClass = clazz.isAnonymousClass() ? clazz.getSuperclass() : clazz;                jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(enumClass, enumClass);                if (jdbcHandlerMap == null) {                    register(enumClass, getInstance(enumClass, defaultEnumTypeHandler));                    return typeHandlerMap.get(enumClass);                }            } else {                // 查找父类关联的TypeHandler集合,并将其作为clazz对应的TypeHandler集合                jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz);            }        }        // 如果上述查找皆失败,则以NULL_TYPE_HANDLER_MAP作为clazz对应的TypeHandler集合        typeHandlerMap.put(type, jdbcHandlerMap == null ?                NULL_TYPE_HANDLER_MAP : jdbcHandlerMap);        return jdbcHandlerMap;    }
复制代码


  1. 先查找指定 Java 类型对应的 TypeHandler 集合

  2. 如果为空返回 null

  3. 初始化指定 Java 类型的 TypeHandler 集合

  4. 调用 getJdbcHandlerMapForSuperclass()


private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMapForSuperclass(Class<?> clazz) {        Class<?> superclass = clazz.getSuperclass();        if (superclass == null || Object.class.equals(superclass)) {            return null; // 父类为Object或null则查找结束        }        Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(superclass);        if (jdbcHandlerMap != null) {            return jdbcHandlerMap;        } else {            return getJdbcHandlerMapForSuperclass(superclass);        }    }
复制代码


这个方法是返回给定 class 的父类对应的 jdbcHandlerMap 集合,这里用到了递归。

总结

这篇文章主要讲解了类型转换注册类的 TypeHandlerRegistry 的注册方法和根据 Java 类型获取对应的 TypeHandler 实例的功能,注册类是重要的一个类,Mybatis 的类型转换都需要在这个类进行注册才能实现类型转换

发布于: 刚刚阅读数: 5
用户头像

还未添加个人签名 2020-02-29 加入

公众号《周结论本人》,多平台优质博主

评论

发布
暂无评论
聊聊Mybatis的类型转换注册类TypeHandlerRegistry_11月月更_周杰伦本人_InfoQ写作社区