天天看點

聊聊Mybatis的類型轉換注冊類TypeHandlerRegistry

聊聊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對應的執行個體

擷取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);
        }
    }
           

總結