欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  php教程

mybatis源码分析之TypeHandler

程序员文章站 2022-03-21 12:05:30
...
分析了MapperMethod从创建到执行的过程,MapperMethod的执行包括执行sql返回结果.

在执行sql和返回结果的过程中就会涉及到参数类型的转换,这个过程是通过TypeHandler来处理的.关于TypeHandler官网有比较详细的文档http://www.mybatis.org/mybatis-3/zh/configuration.html#typeHandlers,文档主要说明了如何使用TypeHandler,在下面的分析中将重点分析与TypeHandler有关的源码.

1.配置

MyBatis有默认的类型处理器,如果需要自定义配置也相当简单,在mybatis-config.xml里添加如下配置:

<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

下面分析配置读取设置的过程,在XMLConfigBuilder中

   /**
     * 读取配置文件组装configuration
     * @param root 配置文件的configuration节点
     */
  private void parseConfiguration(XNode root) {    try {      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

在以上源码中有一行

typeHandlerElement(root.evalNode("typeHandlers"));

再来看typeHandlerElement这个方法

/**
   * 读取typeHandlers配置并注册
   * @param parent 配置文件typeHandlers节点
   * @throws Exception
   */
  private void typeHandlerElement(XNode parent) throws Exception {    if (parent != null) {      for (XNode child : parent.getChildren()) {        if ("package".equals(child.getName())) {
          String typeHandlerPackage = child.getStringAttribute("name");          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
          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);
          }
        }
      }
    }
  }

if和else中的代码逻辑对应了typeHandler的两种配置方式.最后都会调用

typeHandlerRegistry.register()

mybatis源码分析之TypeHandler

以上是TypeHandler与TypeHandlerRegistry,Configuration,BaseTypeHandler之间的关系.

2.设置参数

设置参数时先调用ParameterHandler.setParameters(),然后在setParameters()里获取相应的typeHandler,最后调用typeHandler.setParameter()

mybatis源码分析之TypeHandler

再来看看BaseTypeHandler的setParameter方法

当parameter不为null时调用的是setNonNullParameter,也就是说子类需要实现setNonNullParameter

BigIntegerTypeHandler的源码:

  public void setNonNullParameter(PreparedStatement ps, int i, BigInteger parameter, JdbcType jdbcType) throws SQLException {
    ps.setBigDecimal(i, new BigDecimal(parameter));
  }

至此,TypeHandler的作用已经大致分析完毕了.

相关标签: mybatis