• Ibatis的类型处理器TypeHandler解析


      Ibatis允许用户像在hibernate中一样定义自己的类型,但是,用户自定义类型需要与数据库中的字段类型进行对应。它的处理方法是允许我们扩展TypeHandler。Ibatis框架在处理该数据类型时就会自动调用TypeHandler进行类型转换,非常方便,ibatis中所有的类型都有它自己的TypeHandler,只是一些常用的数据类类型它已经给我们实现了而已。

      在配置文件中,我们有两个地方可以配置这种处理器。

      第一个地方是sqlMap文件中标签ResultMap或者ParameterMap中的TypeHandler属性,这里配置的handler是局部属性,只会在该ResultMap中才会进行转换。

    <resultMap id="UserOrder" class="UserOrderDO" groupBy="id">
             ......
            <result property="tripType" column="trip_Type"
             typeHandler="com.taobao.et.biz.dal.common.EnumTypeHandlerCallBack"/>
              ......
    </resultMap>

       第二个地方是sqlMapConfig文件中的标签typeHandlers中配置typeHandle子标签,这里配置的标签是全局属性,任何只要匹配该子标签的地方都会自动使用该Handler.

    <typeHandlers>
    <typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>
    </typeHandlers>

      例如这里的全局配置,如果此时某个数据库字段的jdbcType是CLOB类型,并且映射的JavaType类型是字符串类型,那么就会自动调用这里的callback来实行类型转换。

      那么Ibatis是如何确定使用哪一个TypeHandler的呢?!

          它会在自己的局部区域寻找是否在配置文件中配置了Handler,找到了就使用这个handler,如果没有找到,就会查找是否有全局handler,也就是第二种方式配置的handler,这里要注意,可能我们也没有在全局配置文件中配置handler,此时,Ibatis就会根据实际类型配置默认的handler。

          我们来看一些关键代码,按照查找步骤,这里我去掉了异常,只看关键的部分。

          第一步:从局部Reultmap中取出配置属性。

         String propertyName = childAttributes.getProperty("property");
            String nullValue = childAttributes.getProperty("nullValue");
            String jdbcType = childAttributes.getProperty("jdbcType");
            String javaType = childAttributes.getProperty("javaType");
            String columnName = childAttributes.getProperty("column");
            String columnIndex = childAttributes.getProperty("columnIndex");
            String statementName = childAttributes.getProperty("select");
            String resultMapName = childAttributes.getProperty("resultMap");
            String callback = childAttributes.getProperty("typeHandler");
            callback = vars.typeHandlerFactory.resolveAlias(callback);
            javaType = vars.typeHandlerFactory.resolveAlias(javaType);
            TypeHandler handler = null;
            if (callback != null) { // 注意这里,如果配置了就使用这个配置的handler
                Object impl = Resources.classForName(callback).newInstance();
                if (impl instanceof TypeHandlerCallback) {
                  handler = new CustomTypeHandler((TypeHandlerCallback) impl);
                } else if (impl instanceof TypeHandler) {
                  handler = (TypeHandler) impl;
                } else {
                  throw new NestedRuntimeException ("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
                }
            } else {//如果没有配置,就到这里来找
                      handler = resolveTypeHandler(vars.client.getDelegate().getTypeHandlerFactory(), vars.currentResultMap.getResultClass(), propertyName, javaType, jdbcType, true);
            }

      第二步,如果局部配置中没有找到,就到下面去找。

    public TypeHandler resolveTypeHandler(TypeHandlerFactory typeHandlerFactory, Class clazz, String propertyName, String javaType, String jdbcType, boolean useSetterToResolve) {
        TypeHandler handler = null;
        if (clazz == null) {
          // Unknown
          handler = typeHandlerFactory.getUnkownTypeHandler();
        } else if (DomTypeMarker.class.isAssignableFrom(clazz)) {
          // DOM
          handler = typeHandlerFactory.getTypeHandler(String.class, jdbcType);
        } else if (java.util.Map.class.isAssignableFrom(clazz)) {
          // Map
          if (javaType == null) {
            handler = typeHandlerFactory.getUnkownTypeHandler(); //BUG 1012591 - typeHandlerFactory.getTypeHandler(java.lang.Object.class, jdbcType);
          } else {
            try {
              Class javaClass = Resources.classForName(javaType);
              handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
            } catch (Exception e) {
              throw new NestedRuntimeException("Error.  Could not set TypeHandler.  Cause: " + e, e);
            }
          }
        } else if (typeHandlerFactory.getTypeHandler(clazz, jdbcType) != null) {
          // Primitive
          handler = typeHandlerFactory.getTypeHandler(clazz, jdbcType);
        } else {
          // JavaBean
          if (javaType == null) {
            if (useSetterToResolve) {
              Class type = PROBE.getPropertyTypeForSetter(clazz, propertyName);
              handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
            } else {
              Class type = PROBE.getPropertyTypeForGetter(clazz, propertyName);
              handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
            }
          } else {
            try {
              Class javaClass = Resources.classForName(javaType);
              handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
            } catch (Exception e) {
              throw new NestedRuntimeException("Error.  Could not set TypeHandler.  Cause: " + e, e);
            }
          }
        }
        return handler;
      }
    1. 相信大家已经很明白了,其实要找一个Handler,主要就是需要javaType和jdbcType,而这两个参数要么通过反射得到,要么通过配置文件中得到。因此,为了明确我们一般都在配置文件中进行申明。
    2. 最后来看一点 typeHandlerFactory.getTypeHandler(clazz, jdbcType)是怎么实现的。
    public TypeHandler getTypeHandler(Class type, String jdbcType) {
        Map jdbcHandlerMap = (Map) typeHandlerMap.get(type);//首先根据JAVA类型
        TypeHandler handler = null;
        if (jdbcHandlerMap != null) {
          handler = (TypeHandler) jdbcHandlerMap.get(jdbcType);//每个JDBC类型
          if (handler == null) {
            handler = (TypeHandler) jdbcHandlerMap.get(null);
          }
        }
        return handler;
      }

      其实一个Handler=javaType+jdbcType 。

  • 相关阅读:
    队列数据结构与算法JavaScript描述(5)
    栈数据结构与算法Javascript描述(4)
    散列数据结构与算法JavaScript描述(8)
    Evevt Loop、任务队列、定时器等
    OSGi初始篇
    应用服务平台与应用服务器
    数据源相关规范整理
    新手入门:教您最优的J2EE学习经验和流程
    TableView的使用
    Strategy
  • 原文地址:https://www.cnblogs.com/lcngu/p/5297396.html
Copyright © 2020-2023  润新知