Configuration--typeHandlers(三-7)

本文深入探讨了MyBatis的typeHandlers标签,解析了它在Java类型和数据库字段类型转换中的作用。通过分析源码,展示了typeHandlerElement方法如何处理并注册TypeHandler,特别提到了当子标签为package时的处理方式,以及MappedTypes注解在注册过程中的应用。文章最后指出,TypeHandlerRegistry的核心是TYPE_HANDLER_MAP,这是一个存储Java类型及其对应不同JDBC类型的typeHandler的映射结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇文章我们继续来了解typeHandlers标签,这个标签的作用主要就是用于Java类型和数据库字段类型的相互转换.

基本用法为:

    <typeHandlers>
        <typeHandler handler="" javaType="" jdbcType=""></typeHandler>
        <package name=""></package>
    </typeHandlers>

我们直接来看typeHandlerElement(root.evalNode(“typeHandlers”))方法的代码:

  private void typeHandlerElement(XNode parent) throws Exception {
    if (parent != null) {

      // 遍历typeHandlers下所有子标签
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          // 若是package子标签,则使用typeHandlerRegistry的register方法去注册类型处理器
          // typeHandlerRegistry也是在BaseBuilder构造方法中从Configuration拿出来的(和typeAliasRegistry一样)
          String typeHandlerPackage = child.getStringAttribute("name");
          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
          String javaTypeName = child.getStringAttribute("javaType");
          String jdbcTypeName = child.getStringAttribute("jdbcType");
          String handlerTypeName = child.getStringAttribute("handler");
          // 通过别名获取javaType的Class对象
          Class<?> javaTypeClass = resolveClass(javaTypeName);
          // 通过jdbcType获取JdbcType对象
          JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
          // 通过别名获取handler的Class对象
          Class<?> typeHandlerClass = resolveClass(handlerTypeName);
          // 通过不同的条件去注册类型处理器
          if (javaTypeClass != null) {
            if (jdbcType == null) {
              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
            } else {
              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
            }
          } else {
            typeHandlerRegistry.register(typeHandlerClass);
          }
        }
      }
    }
  }

从上述代码能看出,最终都将调用typeHandlerRegistryregister方法的各中重载形式.

我们先来看子标签为package时,使用的注册一个包中所有的typeHandlerregister方法:

  public void register(String packageName) {
    // 查找该包下所有实现了TypeHandler接口的类
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
    Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
    for (Class<?> type : handlerSet) {
      // 当该类不是内部内或接口或者抽象类时,注册类型处理器
      if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
        register(type);
      }
    }
  }

  public void register(Class<?> typeHandlerClass) {
    boolean mappedTypeFound = false;
    // 看该类上是否使用了MappedTypes注解
    MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
    if (mappedTypes != null) {
      for (Class<?> javaTypeClass : mappedTypes.value()) {
        register(javaTypeClass, typeHandlerClass);
        mappedTypeFound = true;
      }
    }
    if (!mappedTypeFound) {
      register(getInstance(null, typeHandlerClass));
    }
  }

从上述代码中可以看出,若使用了MappedTypes注解,则继续调用register(javaTypeClass, typeHandlerClass)方法:

  public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
  }

  private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
    // 看该类上是否使用了MappedJdbcTypes注解
    MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
    // 最终都是去调用register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler)方法
    if (mappedJdbcTypes != null) {
      for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
        register(javaType, handledJdbcType, typeHandler);
      }
      if (mappedJdbcTypes.includeNullJdbcType()) {
        register(javaType, null, typeHandler);
      }
    } else {
      register(javaType, null, typeHandler);
    }
  }

  public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    if (javaTypeClass != null) {
      // 若javaTypeClass不为null,则调用typeHandlerClass的有参构造方法,构造一个TypeHandler
      try {
        Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
        return (TypeHandler<T>) c.newInstance(javaTypeClass);
      } catch (NoSuchMethodException ignored) {
        // ignored
      } catch (Exception e) {
        throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
      }
    }
    // 若javaTypeClass为null,则调用typeHandlerClass的无参构造方法,构造一个TypeHandler
    try {
      Constructor<?> c = typeHandlerClass.getConstructor();
      return (TypeHandler<T>) c.newInstance();
    } catch (Exception e) {
      throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
    }
  }

我们来看看最终调用的register方法:

  private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
    if (javaType != null) {
      // 查看当前javaType是否有对应的类型处理器,如果没有则新建
      // 如果有,则将该javaType到jdbcType映射对应的类型处理器加入map中
      Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
      if (map == null) {
        map = new HashMap<JdbcType, TypeHandler<?>>();
        TYPE_HANDLER_MAP.put(javaType, map);
      }
      map.put(jdbcType, handler);
      // 若是对包装类的javaType注册处理器映射器,则同时也给对应的基本类型注册
      if (reversePrimitiveMap.containsKey(javaType)) {
        register(reversePrimitiveMap.get(javaType), jdbcType, handler);
      }
    }
    // 所有的映射器Class和实例的映射map
    ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
  }

综上,我们可以看出,TypeHandlerRegistry内部最重要的是TYPE_HANDLER_MAP.是一个Map结构,key为java类型,value还是一个Map结构,该Map结构的key是jdbc类型,value是一个typeHandler.

所以,我们可以看出,一个java类型,可以对应多个jdbc类型,对应的每个jdbc类型都有其typeHandler.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值