【Mybatis】Mybatis源码之parameterMap标签解析

289 阅读3分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

时序图

sequenceDiagram
participant A as XMLMapperBuilder
participant B as MapperBuilderAssistant
participant C as ParameterMapping
participant D as TypeHandlerRegistry

A ->> B : buildParameterMapping
B ->> C : Builder
B ->> C : build
C ->> C : resolveTypeHandler
C ->> D : getTypeHandler
D ->> D : getJdbcHandlerMap
D -->> C : TypeHandler
C -->> A : ParameterMapping

详细步骤

XMLMapperBuilder#configurationElement

/**
 * 解析映射文件的下层节点
 * @param context 映射文件根节点
 */
private void configurationElement(XNode context) {
    try {
        // 读取当前映射文件namespace
        String namespace = context.getStringAttribute("namespace");
        if (namespace == null || namespace.equals("")) {
            throw new BuilderException("Mapper's namespace cannot be empty");
        }
        builderAssistant.setCurrentNamespace(namespace);
        // 映射文件中其他配置节点的解析
        // 解析缓存标签
        cacheRefElement(context.evalNode("cache-ref"));
        cacheElement(context.evalNode("cache"));
        // 解析参数映射
        parameterMapElement(context.evalNodes("/mapper/parameterMap"));
        // 解析结果集映射
        resultMapElements(context.evalNodes("/mapper/resultMap"));
        // 解析sql标签
        sqlElement(context.evalNodes("/mapper/sql"));
        // 处理各个数据库操作语句
        buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
        throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
}

XMLMapperBuilder#parameterMapElement

/**
 * 参数映射解析
 */
private void parameterMapElement(List<XNode> list) {
    // 解析所有的parameterMap标签
    for (XNode parameterMapNode : list) {
        // 解析单个parameterMap标签中的属性
        String id = parameterMapNode.getStringAttribute("id");
        String type = parameterMapNode.getStringAttribute("type");
        Class<?> parameterClass = resolveClass(type);
        // 解析parameterMap标签内部具体的映射关系
        List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
        List<ParameterMapping> parameterMappings = new ArrayList<>();
        for (XNode parameterNode : parameterNodes) {
            // 解析parameter标签中的映射属性
            String property = parameterNode.getStringAttribute("property");
            String javaType = parameterNode.getStringAttribute("javaType");
            String jdbcType = parameterNode.getStringAttribute("jdbcType");
            String resultMap = parameterNode.getStringAttribute("resultMap");
            String mode = parameterNode.getStringAttribute("mode");
            String typeHandler = parameterNode.getStringAttribute("typeHandler");
            Integer numericScale = parameterNode.getIntAttribute("numericScale");
            // 根据配置参数模式枚举,若无配置,则为null
            ParameterMode modeEnum = resolveParameterMode(mode);
            // 根据配置解析javaType,若无配置,则为null
            Class<?> javaTypeClass = resolveClass(javaType);
            // 根据配置解析jdbcType,若无配置,则为null
            JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
            // 根据配置解析类型处理器,若无配置,则为null
            Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
            // 解析参数映射
            ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
            parameterMappings.add(parameterMapping);
        }
        // 将解析完成的parameterMap添加到Configuration对象中的parameterMaps属性中
        builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
    }
}

MapperBuilderAssistant#buildParameterMapping

  • 如果javaType为null,则通过反射解析
  • 创建ParameterMapping对象并返回
  • 创建对象时,根据javaType、jdbcType解析类型处理器
public ParameterMapping buildParameterMapping(
        Class<?> parameterType,
        String property,
        Class<?> javaType,
        JdbcType jdbcType,
        String resultMap,
        ParameterMode parameterMode,
        Class<? extends TypeHandler<?>> typeHandler,
        Integer numericScale) {
    resultMap = applyCurrentNamespace(resultMap, true);

    // Class parameterType = parameterMapBuilder.type();
    // 反射获取参数的javaType
    Class<?> javaTypeClass = resolveParameterJavaType(parameterType, property, javaType, jdbcType);
    // 根据配置获取类型处理器
    TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);

    // 若没有配置类型处理器,则在build方法中根据javaType,jdbcType解析类型处理器
    return new ParameterMapping.Builder(configuration, property, javaTypeClass)
            .jdbcType(jdbcType)
            .resultMapId(resultMap)
            .mode(parameterMode)
            .numericScale(numericScale)
            .typeHandler(typeHandlerInstance)
            .build();
}

ParameterMapping#Builder

public Builder(Configuration configuration, String property, Class<?> javaType) {
    parameterMapping.configuration = configuration;
    parameterMapping.property = property;
    parameterMapping.javaType = javaType;
    // 设置参数模式为IN
    parameterMapping.mode = ParameterMode.IN;
}

ParameterMapping#build

public ParameterMapping build() {
    // 解析类型处理器
    resolveTypeHandler();
    // 校验
    validate();
    return parameterMapping;
}

ParameterMapping#resolveTypeHandler

private void resolveTypeHandler() {
    if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) {
        Configuration configuration = parameterMapping.configuration;
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        // 根据javaType和jdbcType解析类型处理器
        parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);
    }
}

TypeHandlerRegistry#getTypeHandler

/**
 * 找出一个类型处理器
 *
 * @param type Java类型
 * @param jdbcType JDBC类型
 * @param <T> 类型处理器的目标类型
 * @return 类型处理器
 */
@SuppressWarnings("unchecked")
private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
    if (ParamMap.class.equals(type)) { // 是ParamMap,不是单一的Java类型
        return null;
    }

    // 现根据Java类型找到对应的jdbcHandlerMap
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);
    TypeHandler<?> handler = null;
    if (jdbcHandlerMap != null) {
        // 根据JDBC类型寻找对应的处理器
        handler = jdbcHandlerMap.get(jdbcType);
        if (handler == null) {
            // 使用null 作为键进行一次找寻,通过本类源码可知当前jdbcHandlerMap可能是EnumMap,也可能是HashMap
            // EnumMap不允许键为null,因此总是返回null,HashMap允许键为null,这并不是一次无用功
            handler = jdbcHandlerMap.get(null);
        }
        if (handler == null) {
            // #591
            // 如果jdbcHandlerMap只有一个类型处理器,就取出他
            handler = pickSoleHandler(jdbcHandlerMap);
        }
    }
    // 返回找到的类型处理器
    // type drives generics here
    return (TypeHandler<T>) handler;
}

TypeHandlerRegistry#getJdbcHandlerMap

private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMap(Type type) {
    // 根据Java类型找到对应的jdbcTypeHandlerMap
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(type);
    if (NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap)) {
        // 对应的jdbcTypeHandlerMap为空,则肯定没有符合的类型处理器
        return null;
    }
    if (jdbcHandlerMap == null && type instanceof Class) {
        // 未找到对应的jdbcTypeHandlerMap
        Class<?> clazz = (Class<?>) type;
        if (Enum.class.isAssignableFrom(clazz)) {
            // 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 {
            // 找寻其父类的处理器
            jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz);
        }
    }
    // 注册进typeHandlerMap
    typeHandlerMap.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap);
    return jdbcHandlerMap;
}

以上便是Mybatis解析parameterMap标签的过程。