在 Mybatis 的基础支持层主要看一下支撑 ORM 实现 的底层代码。

1 反射工具包

1.1Reflector

Reflector 类 主要实现了对 JavaBean 的元数据属性的封装,比如:可读属性列表,可写属性列表;及反射操作的封装,如:属性对应的 setter 方法,getter 方法 的反射调用。源码实现如下:

  1. public class Reflector {
  2. /** JavaBean 的 Class类型,在调用 Reflector 的构造方法时初始化该值 */
  3. private final Class<?> type;
  4. /** 可读的属性列表 */
  5. private final String[] readablePropertyNames;
  6. private final String[] writablePropertyNames;
  7. /** key 属性名,value 该属性名对应的 setter方法调用器 */
  8. private final Map<String, Invoker> setMethods = new HashMap<>();
  9. private final Map<String, Invoker> getMethods = new HashMap<>();
  10. /** key 属性名称,value 该属性 setter方法的返回值类型 */
  11. private final Map<String, Class<?>> setTypes = new HashMap<>();
  12. private final Map<String, Class<?>> getTypes = new HashMap<>();
  13. /** type 的默认构造方法 */
  14. private Constructor<?> defaultConstructor;
  15. /** 所有属性名称的集合 */
  16. private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
  17. /**
  18. * 里面的大部分方法都是通过简单的 JDK反射操作 实现的
  19. * @param clazz
  20. */
  21. public Reflector(Class<?> clazz) {
  22. type = clazz;
  23. addDefaultConstructor(clazz);
  24. // 处理 clazz 中的 所有getter方法,填充 getMethods集合 和 getTypes集合
  25. addGetMethods(clazz);
  26. addSetMethods(clazz);
  27. // 处理没有 getter、setter方法 的字段
  28. addFields(clazz);
  29. // 根据 getMethods、setMethods集合 初始化可读、可写的属性
  30. readablePropertyNames = getMethods.keySet().toArray(new String[0]);
  31. writablePropertyNames = setMethods.keySet().toArray(new String[0]);
  32. // 初始化 caseInsensitivePropertyMap集合,key 属性名的大写,value 属性名
  33. for (String propName : readablePropertyNames) {
  34. caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
  35. }
  36. for (String propName : writablePropertyNames) {
  37. caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
  38. }
  39. }
  40. }

1.2 ReflectorFactory

顾名思义,Reflector 的工厂模式,跟大部分工厂类一样,里面肯定有通过标识获取对象的方法。类的设计也遵照了 接口,实现类的模式,虽然本接口只有一个默认实现。

  1. public interface ReflectorFactory {
  2. boolean isClassCacheEnabled();
  3. void setClassCacheEnabled(boolean classCacheEnabled);
  4. /**
  5. * 主要看一下这个方法,通过 JavaBean 的 clazz 获取该 JavaBean 对应的 Reflector
  6. */
  7. Reflector findForClass(Class<?> type);
  8. }
  9. public class DefaultReflectorFactory implements ReflectorFactory {
  10. private boolean classCacheEnabled = true;
  11. /** 大部分容器及工厂设计模式的管用伎俩,key:JavaBean的clazz,value:JavaBean对应的Reflector实例 */
  12. private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
  13. /**
  14. * 实例化一个 ConcurrentMap全局变量,然后暴露一个方法从 map 中获取目标对象,这种设计是很多框架都会用的
  15. */
  16. @Override
  17. public Reflector findForClass(Class<?> type) {
  18. if (classCacheEnabled) {
  19. // synchronized (type) removed see issue #461
  20. return reflectorMap.computeIfAbsent(type, Reflector::new);
  21. } else {
  22. return new Reflector(type);
  23. }
  24. }
  25. public DefaultReflectorFactory() {
  26. }
  27. @Override
  28. public boolean isClassCacheEnabled() {
  29. return classCacheEnabled;
  30. }
  31. @Override
  32. public void setClassCacheEnabled(boolean classCacheEnabled) {
  33. this.classCacheEnabled = classCacheEnabled;
  34. }
  35. }
  36. /**
  37. * 支持定制化 ReflectorFactory
  38. */
  39. public class CustomReflectorFactory extends DefaultReflectorFactory {
  40. }

1.3 ObjectFactory

该类也是接口加一个默认实现类,并且支持自定义扩展,Mybatis 中有很多这样的设计方式。

  1. /**
  2. * MyBatis uses an ObjectFactory to create all needed new Objects.
  3. */
  4. public interface ObjectFactory {
  5. /**
  6. * Sets configuration properties.
  7. */
  8. default void setProperties(Properties properties) {
  9. // NOP
  10. }
  11. /**
  12. * Creates a new object with default constructor.
  13. */
  14. <T> T create(Class<T> type);
  15. /**
  16. * Creates a new object with the specified constructor and params.
  17. */
  18. <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
  19. /**
  20. * Returns true if this object can have a set of other objects.
  21. * It's main purpose is to support non-java.util.Collection objects like Scala collections.
  22. */
  23. <T> boolean isCollection(Class<T> type);
  24. }
  25. /**
  26. * ObjectFactory接口 的唯一直接实现,反射工厂,根据传入的参数列表,选择
  27. * 合适的构造函数实例化对象,不传参数,则直接调用其无参构造方法
  28. */
  29. public class DefaultObjectFactory implements ObjectFactory, Serializable {
  30. private static final long serialVersionUID = -8855120656740914948L;
  31. @Override
  32. public <T> T create(Class<T> type) {
  33. return create(type, null, null);
  34. }
  35. @SuppressWarnings("unchecked")
  36. @Override
  37. public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  38. Class<?> classToCreate = resolveInterface(type);
  39. // we know types are assignable
  40. return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  41. }
  42. /**
  43. * 通过反射来实例化给定的类,如果调用无参构造方法,则直接 constructor.newInstance()
  44. * 如果有参,则根据参数类型和参数值进行调用
  45. */
  46. private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  47. try {
  48. Constructor<T> constructor;
  49. if (constructorArgTypes == null || constructorArgs == null) {
  50. constructor = type.getDeclaredConstructor();
  51. try {
  52. return constructor.newInstance();
  53. } catch (IllegalAccessException e) {
  54. if (Reflector.canControlMemberAccessible()) {
  55. constructor.setAccessible(true);
  56. return constructor.newInstance();
  57. } else {
  58. throw e;
  59. }
  60. }
  61. }
  62. constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
  63. try {
  64. return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
  65. } catch (IllegalAccessException e) {
  66. if (Reflector.canControlMemberAccessible()) {
  67. constructor.setAccessible(true);
  68. return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
  69. } else {
  70. throw e;
  71. }
  72. }
  73. } catch (Exception e) {
  74. String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
  75. .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
  76. String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
  77. .stream().map(String::valueOf).collect(Collectors.joining(","));
  78. throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
  79. }
  80. }
  81. }

2 类型转换

类型转换是实现 ORM 的重要一环,由于数据库中的数据类型与 Java 语言 的数据类型并不对等,所以在 PrepareStatement 为 sql 语句 绑定参数时,需要从 Java 类型 转换成 JDBC 类型,而从结果集获取数据时,又要将 JDBC 类型 转换成 Java 类型,Mybatis 使用 TypeHandler 完成了上述的双向转换。

2.1 JdbcType

Mybatis 通过 JdbcType 这个枚举类型代表了 JDBC 中的数据类型。

  1. /**
  2. * 该枚举类描述了 JDBC 中的数据类型
  3. */
  4. public enum JdbcType {
  5. /*
  6. * This is added to enable basic support for the
  7. * ARRAY data type - but a custom type handler is still required
  8. */
  9. ARRAY(Types.ARRAY),
  10. BIT(Types.BIT),
  11. TINYINT(Types.TINYINT),
  12. SMALLINT(Types.SMALLINT),
  13. INTEGER(Types.INTEGER),
  14. BIGINT(Types.BIGINT),
  15. FLOAT(Types.FLOAT),
  16. REAL(Types.REAL),
  17. DOUBLE(Types.DOUBLE),
  18. NUMERIC(Types.NUMERIC),
  19. DECIMAL(Types.DECIMAL),
  20. CHAR(Types.CHAR),
  21. VARCHAR(Types.VARCHAR),
  22. LONGVARCHAR(Types.LONGVARCHAR),
  23. DATE(Types.DATE),
  24. TIME(Types.TIME),
  25. TIMESTAMP(Types.TIMESTAMP),
  26. BINARY(Types.BINARY),
  27. VARBINARY(Types.VARBINARY),
  28. LONGVARBINARY(Types.LONGVARBINARY),
  29. NULL(Types.NULL),
  30. OTHER(Types.OTHER),
  31. BLOB(Types.BLOB),
  32. CLOB(Types.CLOB),
  33. BOOLEAN(Types.BOOLEAN),
  34. CURSOR(-10), // Oracle
  35. UNDEFINED(Integer.MIN_VALUE + 1000),
  36. NVARCHAR(Types.NVARCHAR), // JDK6
  37. NCHAR(Types.NCHAR), // JDK6
  38. NCLOB(Types.NCLOB), // JDK6
  39. STRUCT(Types.STRUCT),
  40. JAVA_OBJECT(Types.JAVA_OBJECT),
  41. DISTINCT(Types.DISTINCT),
  42. REF(Types.REF),
  43. DATALINK(Types.DATALINK),
  44. ROWID(Types.ROWID), // JDK6
  45. LONGNVARCHAR(Types.LONGNVARCHAR), // JDK6
  46. SQLXML(Types.SQLXML), // JDK6
  47. DATETIMEOFFSET(-155), // SQL Server 2008
  48. TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE), // JDBC 4.2 JDK8
  49. TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); // JDBC 4.2 JDK8
  50. public final int TYPE_CODE;
  51. /** 该静态集合维护了 常量编码 与 JdbcType 之间的关系 */
  52. private static Map<Integer,JdbcType> codeLookup = new HashMap<>();
  53. static {
  54. for (JdbcType type : JdbcType.values()) {
  55. codeLookup.put(type.TYPE_CODE, type);
  56. }
  57. }
  58. JdbcType(int code) {
  59. this.TYPE_CODE = code;
  60. }
  61. public static JdbcType forCode(int code) {
  62. return codeLookup.get(code);
  63. }
  64. }

2.2 TypeHandler

TypeHandler 是 Mybatis 中所有类型转换器的顶层接口,主要用于实现数据从 Java 类型 到 JdbcType 类型 的相互转换。

  1. public interface TypeHandler<T> {
  2. /** 通过 PreparedStatement 为 SQL语句 绑定参数时,将数据从 Java类型 转换为 JDBC类型 */
  3. void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  4. /** 从结果集获取数据时,将数据由 JDBC类型 转换成 Java类型 */
  5. T getResult(ResultSet rs, String columnName) throws SQLException;
  6. T getResult(ResultSet rs, int columnIndex) throws SQLException;
  7. T getResult(CallableStatement cs, int columnIndex) throws SQLException;
  8. }
  9. /**
  10. * 可用于实现自定义的 TypeHandler
  11. */
  12. public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
  13. /**
  14. * 只是处理了一些数据为空的特殊情况,非空数据的处理都交给子类去处理
  15. */
  16. @Override
  17. public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
  18. if (parameter == null) {
  19. if (jdbcType == null) {
  20. throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
  21. }
  22. try {
  23. ps.setNull(i, jdbcType.TYPE_CODE);
  24. } catch (SQLException e) {
  25. throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
  26. + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
  27. + "Cause: " + e, e);
  28. }
  29. } else {
  30. try {
  31. setNonNullParameter(ps, i, parameter, jdbcType);
  32. } catch (Exception e) {
  33. throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
  34. + "Try setting a different JdbcType for this parameter or a different configuration property. "
  35. + "Cause: " + e, e);
  36. }
  37. }
  38. }
  39. @Override
  40. public T getResult(ResultSet rs, String columnName) throws SQLException {
  41. try {
  42. return getNullableResult(rs, columnName);
  43. } catch (Exception e) {
  44. throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e);
  45. }
  46. }
  47. }
  48. public class IntegerTypeHandler extends BaseTypeHandler<Integer> {
  49. /**
  50. * NonNull 就是 NoneNull,非空的意思
  51. */
  52. @Override
  53. public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
  54. throws SQLException {
  55. // IntegerTypeHandler 就调用 PreparedStatement 的 setInt()方法
  56. // BooleanTypeHandler 就调用 PreparedStatement 的 setBoolean()方法
  57. // 其它的基本数据类型,以此类推
  58. ps.setInt(i, parameter);
  59. }
  60. @Override
  61. public Integer getNullableResult(ResultSet rs, String columnName)
  62. throws SQLException {
  63. int result = rs.getInt(columnName);
  64. return result == 0 && rs.wasNull() ? null : result;
  65. }
  66. @Override
  67. public Integer getNullableResult(ResultSet rs, int columnIndex)
  68. throws SQLException {
  69. int result = rs.getInt(columnIndex);
  70. return result == 0 && rs.wasNull() ? null : result;
  71. }
  72. @Override
  73. public Integer getNullableResult(CallableStatement cs, int columnIndex)
  74. throws SQLException {
  75. int result = cs.getInt(columnIndex);
  76. return result == 0 && cs.wasNull() ? null : result;
  77. }
  78. }

TypeHandler 主要用于单个参数的类型转换,如果要将多个列的值转换成一个 Java 对象,可以在映射文件中定义合适的映射规则 <resultMap> 完成映射。

2.3 TypeHandlerRegistry

TypeHandlerRegistry 主要负责管理所有已知的 TypeHandler,Mybatis 在初始化过程中会为所有已知的 TypeHandler 创建对象,并注册到 TypeHandlerRegistry。

  1. // TypeHandlerRegistry 中的核心字段如下
  2. /** 该集合主要用于从结果集读取数据时,将数据从 JDBC类型 转换成 Java类型 */
  3. private final Map<JdbcType, TypeHandler<?>> jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);
  4. /**
  5. * 记录了 Java类型 向指定 JdbcType 转换时,需要使用的 TypeHandler对象。
  6. * 如:String 可能转换成数据库的 char、varchar 等多种类型,所以存在一对多的关系
  7. */
  8. private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
  9. /** key:TypeHandler 的类型;value:该 TypeHandler类型 对应的 TypeHandler对象 */
  10. private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();

1、注册 TypeHandler 对象
TypeHandlerRegistry 中的 register()方法 实现了注册 TypeHandler 对象 的功能,该方法存在多种重载,但大多数 register()方法 最终都会走 register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) 的处理逻辑,该重载方法中分别指定了 TypeHandler 能够处理的 Java 类型、JDBC 类型、TypeHandler 对象。

  1. /**
  2. * TypeHandlerRegistry 中对 register()方法 实现了多种重载,本 register()方法
  3. * 被很多重载方法调用,用来完成注册功能。
  4. */
  5. private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
  6. if (javaType != null) {
  7. Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);
  8. if (map == null || map == NULL_TYPE_HANDLER_MAP) {
  9. map = new HashMap<>();
  10. typeHandlerMap.put(javaType, map);
  11. }
  12. map.put(jdbcType, handler);
  13. }
  14. allTypeHandlersMap.put(handler.getClass(), handler);
  15. }

另外,TypeHandlerRegistry 还提供了扫描并注册指定包目录下 TypeHandler 实现类 的 register()方法 重载。

  1. /**
  2. * 从指定 包名packageName 中获取自定义的 TypeHandler实现类
  3. */
  4. public void register(String packageName) {
  5. ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
  6. // 查找指定包下的 TypeHandler接口实现类
  7. resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
  8. Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
  9. for (Class<?> type : handlerSet) {
  10. // 忽略掉 内部类、接口 及 抽象类
  11. if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
  12. register(type);
  13. }
  14. }
  15. }

最后看一下 TypeHandlerRegistry 的构造方法,其通过多种 register()方法 重载,完成了所有已知的 TypeHandler 的重载。

  1. /**
  2. * 进行 Java 及 JDBC基本数据类型 的 TypeHandler 注册
  3. * 除了注册 Mybatis 提供的 基本TypeHandler 外,我们也可以添加自定义的 TypeHandler
  4. * 接口实现,在 mybatis-config.xml配置文件 中 <typeHandlers>节点 下添加相应的
  5. * <typeHandlers>节点配置,并指定自定义的 TypeHandler实现类。Mybatis 在初始化时
  6. * 会解析该节点,并将 TypeHandler类型 的对象注册到 TypeHandlerRegistry 中供 Mybatis 后续使用
  7. */
  8. public TypeHandlerRegistry() {
  9. register(Boolean.class, new BooleanTypeHandler());
  10. register(boolean.class, new BooleanTypeHandler());
  11. register(JdbcType.BOOLEAN, new BooleanTypeHandler());
  12. register(JdbcType.BIT, new BooleanTypeHandler());
  13. register(Byte.class, new ByteTypeHandler());
  14. register(byte.class, new ByteTypeHandler());
  15. register(JdbcType.TINYINT, new ByteTypeHandler());
  16. register(Short.class, new ShortTypeHandler());
  17. register(short.class, new ShortTypeHandler());
  18. register(JdbcType.SMALLINT, new ShortTypeHandler());
  19. register(Integer.class, new IntegerTypeHandler());
  20. register(int.class, new IntegerTypeHandler());
  21. register(JdbcType.INTEGER, new IntegerTypeHandler());
  22. register(Long.class, new LongTypeHandler());
  23. register(long.class, new LongTypeHandler());
  24. register(Float.class, new FloatTypeHandler());
  25. register(float.class, new FloatTypeHandler());
  26. register(JdbcType.FLOAT, new FloatTypeHandler());
  27. register(Double.class, new DoubleTypeHandler());
  28. register(double.class, new DoubleTypeHandler());
  29. register(JdbcType.DOUBLE, new DoubleTypeHandler());
  30. register(Reader.class, new ClobReaderTypeHandler());
  31. register(String.class, new StringTypeHandler());
  32. register(String.class, JdbcType.CHAR, new StringTypeHandler());
  33. register(String.class, JdbcType.CLOB, new ClobTypeHandler());
  34. register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
  35. register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());
  36. register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
  37. register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
  38. register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
  39. register(JdbcType.CHAR, new StringTypeHandler());
  40. register(JdbcType.VARCHAR, new StringTypeHandler());
  41. register(JdbcType.CLOB, new ClobTypeHandler());
  42. register(JdbcType.LONGVARCHAR, new StringTypeHandler());
  43. register(JdbcType.NVARCHAR, new NStringTypeHandler());
  44. register(JdbcType.NCHAR, new NStringTypeHandler());
  45. register(JdbcType.NCLOB, new NClobTypeHandler());
  46. register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
  47. register(JdbcType.ARRAY, new ArrayTypeHandler());
  48. register(BigInteger.class, new BigIntegerTypeHandler());
  49. register(JdbcType.BIGINT, new LongTypeHandler());
  50. register(BigDecimal.class, new BigDecimalTypeHandler());
  51. register(JdbcType.REAL, new BigDecimalTypeHandler());
  52. register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
  53. register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
  54. register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());
  55. register(Instant.class, new InstantTypeHandler());
  56. register(LocalDateTime.class, new LocalDateTimeTypeHandler());
  57. register(LocalDate.class, new LocalDateTypeHandler());
  58. register(LocalTime.class, new LocalTimeTypeHandler());
  59. register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());
  60. register(OffsetTime.class, new OffsetTimeTypeHandler());
  61. register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());
  62. register(Month.class, new MonthTypeHandler());
  63. register(Year.class, new YearTypeHandler());
  64. register(YearMonth.class, new YearMonthTypeHandler());
  65. register(JapaneseDate.class, new JapaneseDateTypeHandler());
  66. }

2、查找 TypeHandler
TypeHandlerRegistry 其实就是一个容器,前面注册了一堆东西,也就是为了方便获取,其对应的方法为 getTypeHandler(),该方法也存在多种重载,其中最重要的一个重载为 getTypeHandler(Type type, JdbcType jdbcType),它会根据指定的 Java 类型 和 JdbcType 类型 查找相应的 TypeHandler 对象。

  1. /**
  2. * 获取 TypeHandler对象
  3. * getTypeHandler()方法 亦存在多种重载,而本重载方法被其它多个重载方法调用
  4. */
  5. private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
  6. if (ParamMap.class.equals(type)) {
  7. return null;
  8. }
  9. // Java数据类型 与 JDBC数据类型 的关系往往是一对多,
  10. // 所以一般会先根据 Java数据类型 获取 Map<JdbcType, TypeHandler<?>>对象
  11. // 再根据 JDBC数据类型 获取对应的 TypeHandler对象
  12. Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);
  13. TypeHandler<?> handler = null;
  14. if (jdbcHandlerMap != null) {
  15. handler = jdbcHandlerMap.get(jdbcType);
  16. if (handler == null) {
  17. handler = jdbcHandlerMap.get(null);
  18. }
  19. if (handler == null) {
  20. // #591
  21. handler = pickSoleHandler(jdbcHandlerMap);
  22. }
  23. }
  24. // type drives generics here
  25. return (TypeHandler<T>) handler;
  26. }

除了 Mabatis 本身自带的 TypeHandler 实现,我们还可以添加自定义的 TypeHandler 实现类,在配置文件 mybatis-config.xml 中的 <typeHandler> 标签下配置好 自定义 TypeHandler,Mybatis 就会在初始化时解析该标签内容,完成 自定义 TypeHandler 的注册。