相关文章推荐
风流倜傥的麦片  ·  第三期 | ...·  2 月前    · 
痴情的啄木鸟  ·  electron ...·  1 年前    · 
卖萌的眼镜  ·  Error_ Requires Babel ...·  1 年前    · 
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标签的过程。

  • 私信