TypeHandlerRegistry源码简单分析

回顾

上一次我们分析了TypeHandler的源码,了解了Mybatis内部的类型处理器的实现,本篇就来简要分析一下如何去注册TypeHandler。

类型处理器注册器

类型处理器注册器既能完成类型处理器的注册功能,同时也能对类型处理器进行统筹管理,其内部定义了集合来进行类型处理器的存取,同时定义了存取方法。

【TypeHandlerRegistry内部静态变量】

  //枚举类JdbcType作为键,完成数据库类型与类型处理器的对应注册
  private final Map> JDBC_TYPE_HANDLER_MAP = new EnumMap>(JdbcType.class);
  //Java类型作为键,JdbcType与TypeHandler的映射关系作为value,完成Java类型、数据库类型和类型处理器三者的对应注册
  private final Map>> TYPE_HANDLER_MAP = new HashMap>>();
   //对未知类型的注册,如Object
  private final TypeHandler UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
  //保存着所有的类型处理器,是以类型处理器的类类型为键值保存的,它可以统筹所有的类型处理器
  private final Map, TypeHandler> ALL_TYPE_HANDLERS_MAP = new HashMap, TypeHandler>();

【基础类型处理器的对内注册】

  • 对内注册是指Mybatis对内置的TypeHandler的注册过程
  • 基础类型处理器的注册完成在TypeHandlerRegistry的构造函数中
public TypeHandlerRegistry() {
    register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
    register(JdbcType.BIT, new BooleanTypeHandler());

    register(Byte.class, new ByteTypeHandler());
    register(byte.class, new ByteTypeHandler());
    register(JdbcType.TINYINT, new ByteTypeHandler());

    register(Short.class, new ShortTypeHandler());
    register(short.class, new ShortTypeHandler());
    register(JdbcType.SMALLINT, new ShortTypeHandler());

    register(Integer.class, new IntegerTypeHandler());
    register(int.class, new IntegerTypeHandler());
    register(JdbcType.INTEGER, new IntegerTypeHandler());

    register(Long.class, new LongTypeHandler());
    register(long.class, new LongTypeHandler());

    register(Float.class, new FloatTypeHandler());
    register(float.class, new FloatTypeHandler());
    register(JdbcType.FLOAT, new FloatTypeHandler());

    register(Double.class, new DoubleTypeHandler());
    register(double.class, new DoubleTypeHandler());
    register(JdbcType.DOUBLE, new DoubleTypeHandler());

    register(Reader.class, new ClobReaderTypeHandler());
    register(String.class, new StringTypeHandler());
    register(String.class, JdbcType.CHAR, new StringTypeHandler());
    register(String.class, JdbcType.CLOB, new ClobTypeHandler());
    register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
    register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
    register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
    register(JdbcType.CHAR, new StringTypeHandler());
    register(JdbcType.VARCHAR, new StringTypeHandler());
    register(JdbcType.CLOB, new ClobTypeHandler());
    register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
    register(JdbcType.NVARCHAR, new NStringTypeHandler());
    register(JdbcType.NCHAR, new NStringTypeHandler());
    register(JdbcType.NCLOB, new NClobTypeHandler());

    register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
    register(JdbcType.ARRAY, new ArrayTypeHandler());

    register(BigInteger.class, new BigIntegerTypeHandler());
    register(JdbcType.BIGINT, new LongTypeHandler());

    register(BigDecimal.class, new BigDecimalTypeHandler());
    register(JdbcType.REAL, new BigDecimalTypeHandler());
    register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
    register(JdbcType.NUMERIC, new BigDecimalTypeHandler());

    register(InputStream.class, new BlobInputStreamTypeHandler());
    register(Byte[].class, new ByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
    register(byte[].class, new ByteArrayTypeHandler());
    register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
    register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.BLOB, new BlobTypeHandler());

    register(Object.class, UNKNOWN_TYPE_HANDLER);
    register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
    register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);

    register(Date.class, new DateTypeHandler());
    register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
    register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
    register(JdbcType.TIMESTAMP, new DateTypeHandler());
    register(JdbcType.DATE, new DateOnlyTypeHandler());
    register(JdbcType.TIME, new TimeOnlyTypeHandler());

    register(java.sql.Date.class, new SqlDateTypeHandler());
    register(java.sql.Time.class, new SqlTimeTypeHandler());
    register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

    // mybatis-typehandlers-jsr310
    try {
      register("java.time.Instant", "org.apache.ibatis.type.InstantTypeHandler");
      register("java.time.LocalDateTime", "org.apache.ibatis.type.LocalDateTimeTypeHandler");
      register("java.time.LocalDate", "org.apache.ibatis.type.LocalDateTypeHandler");
      register("java.time.LocalTime", "org.apache.ibatis.type.LocalTimeTypeHandler");
      register("java.time.OffsetDateTime", "org.apache.ibatis.type.OffsetDateTimeTypeHandler");
      register("java.time.OffsetTime", "org.apache.ibatis.type.OffsetTimeTypeHandler");
      register("java.time.ZonedDateTime", "org.apache.ibatis.type.ZonedDateTimeTypeHandler");
    } catch (ClassNotFoundException e) {
      // no JSR-310 handlers
    }

    // issue #273
    register(Character.class, new CharacterTypeHandler());
    register(char.class, new CharacterTypeHandler());
  }

TypeHandlerRegistry提供了多种注册方法,各种注册方法之间也存在着一些调用,现以Integer为例简要分析。

    register(Integer.class, new IntegerTypeHandler());//1
    register(int.class, new IntegerTypeHandler());//与1相同
    register(JdbcType.INTEGER, new IntegerTypeHandler());//2

【1】

  // java type + handler(两者联合注册)
  public  void register(Class javaType, TypeHandler typeHandler) {
    register((Type) javaType, typeHandler);
  }

  private  void register(Type javaType, TypeHandler typeHandler) {
    MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
    if (mappedJdbcTypes != null) {
      for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
        register(javaType, handledJdbcType, typeHandler);
      }
      if (mappedJdbcTypes.includeNullJdbcType()) {
        register(javaType, null, typeHandler);
      }
    } else {
      register(javaType, null, typeHandler);
    }
  }
  • 在对Integer和int与IntegerTypeHandler注册时,采用java type + handler的形式,注册时首先判断TypeHandler是否有MappedJdbcTypes注解指明jdbc类型
  • 有则使用java type + jdbc type + handler模式进行三者联合注册
  • 没有则将jdbcType置为null然后进行三者联合注册
 // java type + jdbc type + handler(三者联合注册)
 // 一般所有的注册方法都会指向本方法

  public  void register(Class type, JdbcType jdbcType, TypeHandler handler) {
    register((Type) type, jdbcType, handler);
  }

  private void register(Type javaType, JdbcType jdbcType, TypeHandler handler) {
    if (javaType != null) {
      Map> map = TYPE_HANDLER_MAP.get(javaType);
      if (map == null) {
        map = new HashMap>();
        TYPE_HANDLER_MAP.put(javaType, map);
      }
      map.put(jdbcType, handler);
    }
    ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
  }
  • javaType不为空时,从TYPE_HANDLER_MAP找出其对应的【JdbcType和TypeHandler】的映射关系,如果关系不存在,则新建一个映射关系。
  • 将这种关系添加到TYPE_HANDLER_MAP中
  • 将jdbcType与handler加到该映射关系中
  • 完成JavaType、JdbcType和TypeHandler三者的注册

【2】

  public void register(JdbcType jdbcType, TypeHandler handler) {
    JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
  }

将JdbcType与TypeHandler映射关系添加到JDBC_TYPE_HANDLER_MAP中

【基础类型处理器的对外注册】

  • Mybatis不仅内置了很多基础的类型处理器,也允许使用者根据需求自定义TypeHandler
  • 为了方便使用者去注册自定义TypeHandler,Mybatis提供了很多注册方法,用户只需要提供自定义处理器的类路径

【Only handler type】

  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) {
      register(getInstance(null, typeHandlerClass));
    }
  }

【java type + handler type】

  public void register(String javaTypeClassName, String typeHandlerClassName) throws ClassNotFoundException {
    register(Resources.classForName(javaTypeClassName), Resources.classForName(typeHandlerClassName));
  }

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

【java type + jdbc type + handler type】

  public void register(Class javaTypeClass, JdbcType jdbcType, Class typeHandlerClass) {
    register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
  }

【scan package】

  public void register(String packageName) {
    ResolverUtil> resolverUtil = new ResolverUtil>();
    resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
    Set>> 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);
      }
    }
  }

用户只需要使用


    

//这样无法指定jdbcType和javaType,可以在自定义TypeHandler上使用注解去指定
//例如:@MappedTypes(String.class) @MappedjdbcTypes(jdbcType.VARCHAR)

或者


    

即可,Mybatis会自动的找到对应的注册方法去注册,一般注册最后都会指到上一小节所提到的【java type + jdbc type + handler(三者联合注册)】方法,它是核心方法。

你可能感兴趣的:(TypeHandlerRegistry源码简单分析)