Mybatis源码分析系列之配置文件加载(二)

Mybatis源码分析系列之配置文件加载(二)
也许文中的一些说明能解决你的困惑。也许有表述不清晰的地方。请大家多多指点。欢迎下方留言。本人准备系统的总结一下各种框架的一些源码。也希望大家能给我提出宝贵意见

我们今天继续上文 传送门:Mybatis源码分析系列之配置文件加载(一)

2.11 typeHandlerElement

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

我们看名字可以理解这个配置文件的含义。在我们日常生产生活中。经常会遇到枚举类。我们在数据库中可能只存放1234这样的标识。但是生产中 我们需要得到标识对应的名称。我们就需要自己定义这个类型处理器来实现。

<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
<!-- 下面是package配置-->
<typeHandlers>
  <package name="org.mybatis.example"/>
</typeHandlers>
<!--处理枚举类型的数据 -->
<typeHandlers>
  <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>
private void typeHandlerElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
       	  //取得package标签中的name
          String typeHandlerPackage = child.getStringAttribute("name");
          //通过register 把 package 全部注册到类型注册器中
          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
        //除了package之外的走下面
        /**
        *获得javaType|jdbcType|handler
        */
          String javaTypeName = child.getStringAttribute("javaType");
          String jdbcTypeName = child.getStringAttribute("jdbcType");
          String handlerTypeName = child.getStringAttribute("handler");
          //解析属性值
          Class<?> javaTypeClass = resolveClass(javaTypeName);
          JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
          Class<?> typeHandlerClass = resolveClass(handlerTypeName);
          //把这些注册到类型注册中心
          if (javaTypeClass != null) {
            if (jdbcType == null) {
              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
            } else {
              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
            }
          } else {
            typeHandlerRegistry.register(typeHandlerClass);
          }
        }
      }
    }
  }
2.11.1 register(String) 方法
public void register(String packageName) {
    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) {
      //Ignore inner classes and interfaces (including package-info.java) and abstract classes
      //其实这块代码真的没什么可说的。大家可以参考(一中我已经写过这块的分析了。)
      if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
        register(type);
      }
    }
  }
2.11.2 register(Class<?> typeHandlerClass)
public void register(Class<?> typeHandlerClass) {
    boolean mappedTypeFound = false;
    //获得注解。注解有几种 我们这列举一下
    MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
    if (mappedTypes != null) {
      for (Class<?> javaTypeClass : mappedTypes.value()) {
      //进行注册
        register(javaTypeClass, typeHandlerClass);
        mappedTypeFound = true;
      }
    }
    if (!mappedTypeFound) {
    //没有注解。也就是没有找到 指定与其关联的 Java 类型列表
      register(getInstance(null, typeHandlerClass));
    }
  }
上面获得注解其实就是@MappedTypes 注解

上面我们说的举例。我就引用官网的一些说明了 1
通过类型处理器的泛型,MyBatis 可以得知该类型处理器处理的 Java 类型,不过这种行为可以通过两种方法改变:

在类型处理器的配置元素(typeHandler element)上增加一个 javaType 属性(比如:javaType="String");
在类型处理器的类上(TypeHandler class)增加一个 @MappedTypes 注解来指定与其关联的 Java 类型列表。 如果在 javaType 属性中也同时指定,则注解方式将被忽略。

可以通过两种方式来指定被关联的 JDBC 类型:

在类型处理器的配置元素上增加一个 jdbcType 属性(比如:jdbcType="VARCHAR");
在类型处理器的类上(TypeHandler class)增加一个 @MappedJdbcTypes 注解来指定与其关联的 JDBC 类型列表。 如果在 jdbcType 属性中也同时指定,则注解方式将被忽略。

当决定在ResultMap中使用某一TypeHandler时,此时java类型是已知的(从结果类型中获得),但是JDBC类型是未知的。 因此Mybatis使用javaType=[TheJavaType], jdbcType=null的组合来选择一个TypeHandler。 这意味着使用@MappedJdbcTypes注解可以限制TypeHandler的范围,同时除非显式的设置,否则TypeHandler在ResultMap中将是无效的。 如果希望在ResultMap中使用TypeHandler,那么设置@MappedJdbcTypes注解的includeNullJdbcType=true即可。 然而从Mybatis 3.4.0开始,如果只有一个注册的TypeHandler来处理Java类型,那么它将是ResultMap使用Java类型时的默认值(即使没有includeNullJdbcType=true)。

2.11.3register(Class<?> javaTypeClass, Class<?> typeHandlerClass)
public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
	//调用2.11.4 
	//说明:getInstance 先通过 getConstructor 获得Constructor 构造器 在通过newInstance 获得 typeHandler实例 
	//getInstance其实就是获得对应java属性的 typeHandler
    register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
  }
2.11.4 register(Class javaType, TypeHandler<? extends T> typeHandler)

源码其实就是一层一层的封装调用。看起来都是方法名称重载。

public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
    register((Type) javaType, typeHandler);
  }
2.11.5 register(Type javaType, TypeHandler<? extends T> typeHandler)
private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
//重要重要。看到没有需要获得注解了。这次获得注解是啥呢。 @MappedJdbcTypes 就是这个注解了
// 注解来指定与其关联的 JDBC 类型列表。
    MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
    if (mappedJdbcTypes != null) {
      for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
        register(javaType, handledJdbcType, typeHandler);
      }
      //发现发现。出现一个新东西。在上面我们提到过。如果希望在ResultMap中使用TypeHandler,那么设置@MappedJdbcTypes注解的includeNullJdbcType=true即可
      if (mappedJdbcTypes.includeNullJdbcType()) {
        register(javaType, null, typeHandler);
      }
    } else {
      register(javaType, null, typeHandler);
    }
  }
2.11.6 register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler)
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
    if (javaType != null) {
    	//通过javaType可以获得jdbcType与TypeHandler的映射关系
      Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
      if (map == null || map == NULL_TYPE_HANDLER_MAP) {
      //新建一个映射关系
        map = new HashMap<JdbcType, TypeHandler<?>>();
       //平且与java类型做映射
        TYPE_HANDLER_MAP.put(javaType, map);
      }
      map.put(jdbcType, handler);
    }
    //存储所有的TypeHandler
    ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
  }

我们已经把所有的注册方法全部写出来了。。其实核心就是要搞清楚java类型与jdbc类型以及typeHandler的关系而已。。产生对应的映射。仅此而已。但是源码就是源码。所有方面都考虑进来了。


  1. Mybatis中文官方文档 ↩︎

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值