1 Star 0 Fork 165

ElonChung / Java-Review

forked from flatfish / Java-Review 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
SSM-Mybatis3-源码解读-第9篇-类型模块.md 42.90 KB
一键复制 编辑 原始数据 按行查看 历史
icanci 提交于 2020-09-07 10:22 . :zap:更新文件名称

SSM - Mybatis3 - 源码解读 - 第9篇 - 类型模块

概述

  • 对应 type

  • 如下所示

1599198155467

1599198197885

  • MyBatis 为简化配置文件提供了别名机制,该机制是类型转换模块的主要功能之一

  • 类型转换模块的另一个功能是实现 JDBC 类型与 Java 类型之间的转换,该功能在为 SQL 语句绑定实参以及映射查询结果集时都会涉及:

    • 在为 SQL 语句绑定实参时,会将数据由 Java 类型转换成 JDBC 类型。
    • 而在映射结果集时,会将数据由 JDBC 类型转换成 Java 类型。
  • 本篇主要讲解的类

TypeHander

  • org.apache.ibatis.type.TypeHandler ,类型转换处理器
public interface TypeHandler<T> {

    // 设置 PreparedStatement 的指定参数
    // ps:PreparedStatement 对象
    // i:参数占位符的位置
    // parameter:参数
    // jdbcType:JDBC类型
    // SQLException 异常
    void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

    // 获得 ResultSet的指定字段
    // rs:ResultSet 对象
    // columnName:字段名
    // 返回结果
    T getResult(ResultSet rs, String columnName) throws SQLException;

    // 获得位置指定的值
    // rs:结果集
    // columnIndex:字段位置
    T getResult(ResultSet rs, int columnIndex) throws SQLException;

    // 获得 CallableStatement 的指定字段的值
    T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}
  • 流程图如下

BaseTypeHandler
  • org.apache.ibatis.type.BaseTypeHandler ,实现 TypeHandler 接口,继承 TypeReference 抽象类,TypeHandler 基础抽象类
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
    @Deprecated
    protected Configuration configuration;

    @Deprecated
    public void setConfiguration(Configuration c) {
        this.configuration = c;
    }

    @Override
    public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        // 参数为空的时候,设置为null
        if (parameter == null) {
            if (jdbcType == null) {
                throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
            }
            try {
                // 设置为null
                ps.setNull(i, jdbcType.TYPE_CODE);
            } catch (SQLException e) {
                throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
                                        + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
                                        + "Cause: " + e, e);
            }
            // 参数非空地时候,设置对应的参数
        } else {
            try {
                setNonNullParameter(ps, i, parameter, jdbcType);
            } catch (Exception e) {
                throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
                                        + "Try setting a different JdbcType for this parameter or a different configuration property. "
                                        + "Cause: " + e, e);
            }
        }
    }

    @Override
    public T getResult(ResultSet rs, String columnName) throws SQLException {
        try {
            return getNullableResult(rs, columnName);
        } catch (Exception e) {
            throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);
        }
    }

    @Override
    public T getResult(ResultSet rs, int columnIndex) throws SQLException {
        try {
            return getNullableResult(rs, columnIndex);
        } catch (Exception e) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set.  Cause: " + e, e);
        }
    }

    @Override
    public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
        try {
            return getNullableResult(cs, columnIndex);
        } catch (Exception e) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement.  Cause: " + e, e);
        }
    }

    // 以下方法由子类实现
    public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

    public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;

    public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;

    public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;

}
子类
  • TypeHandler 有非常多的子类,当然所有子类都是继承自 BaseTypeHandler 抽象类。考虑到篇幅,我们就挑选几个来聊聊。
IntegerTypeHandler
  • org.apache.ibatis.type.IntegerTypeHandler ,继承 BaseTypeHandler 抽象类,Integer 类型的 TypeHandler 实现类。
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
        throws SQLException {
        // 直接设置参数即可
        ps.setInt(i, parameter);
    }

    @Override
    public Integer getNullableResult(ResultSet rs, String columnName)
        throws SQLException {
        // 获得字段的值
        int result = rs.getInt(columnName);
        // 先通过 rs 判断是否空。如果是空就返回null 否则返回 result
        return result == 0 && rs.wasNull() ? null : result;
    }

    @Override
    public Integer getNullableResult(ResultSet rs, int columnIndex)
        throws SQLException {
        // 获得字段的值
        int result = rs.getInt(columnIndex);
         // 先通过 rs 判断是否空。如果是空就返回null 否则返回 result
        return result == 0 && rs.wasNull() ? null : result;
    }

    @Override
    public Integer getNullableResult(CallableStatement cs, int columnIndex)
        throws SQLException {
        // 获得字段的值
        int result = cs.getInt(columnIndex);
         // 先通过 rs 判断是否空。如果是空就返回null 否则返回 result
        return result == 0 && cs.wasNull() ? null : result;
    }
}
DateTypeHandler
  • org.apache.ibatis.type.DateTypeHandler ,继承 BaseTypeHandler 抽象类,Date 类型的 TypeHandler 实现类。
public class DateTypeHandler extends BaseTypeHandler<Date> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType)
        throws SQLException {
        // 将 Date 转换成 Timestamp 类型
        // 然后设置到 ps 中
        ps.setTimestamp(i, new Timestamp(parameter.getTime()));
    }

    @Override
    public Date getNullableResult(ResultSet rs, String columnName)
        throws SQLException {
        // 获得 Timestamp 的值
        Timestamp sqlTimestamp = rs.getTimestamp(columnName);
        if (sqlTimestamp != null) {
            // 将 Timestamp 转换成 Date Timestamp 类型
            return new Date(sqlTimestamp.getTime());
        }
        return null;
    }

    @Override
    public Date getNullableResult(ResultSet rs, int columnIndex)
        throws SQLException {
        Timestamp sqlTimestamp = rs.getTimestamp(columnIndex);
        if (sqlTimestamp != null) {
            return new Date(sqlTimestamp.getTime());
        }
        return null;
    }

    @Override
    public Date getNullableResult(CallableStatement cs, int columnIndex)
        throws SQLException {
        Timestamp sqlTimestamp = cs.getTimestamp(columnIndex);
        if (sqlTimestamp != null) {
            return new Date(sqlTimestamp.getTime());
        }
        return null;
    }
}
DateOnlyTypeHandler
  • org.apache.ibatis.type.DateOnlyTypeHandler ,继承 BaseTypeHandler 抽象类,Date 类型的 TypeHandler 实现类
public class DateOnlyTypeHandler extends BaseTypeHandler<Date> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType)
        throws SQLException {
        // 将 java Date 转换成 sql Date 类型
        ps.setDate(i, new java.sql.Date(parameter.getTime()));
    }

    @Override
    public Date getNullableResult(ResultSet rs, String columnName)
        throws SQLException {
        // 获得 SQL Date的值
        java.sql.Date sqlDate = rs.getDate(columnName);
        if (sqlDate != null) {
           	// 将 SQL Date 转换成 Java Date类型
            return new Date(sqlDate.getTime());
        }
        return null;
    }

    // 下面的方法很简单
    
    @Override
    public Date getNullableResult(ResultSet rs, int columnIndex)
        throws SQLException {
        java.sql.Date sqlDate = rs.getDate(columnIndex);
        if (sqlDate != null) {
            return new Date(sqlDate.getTime());
        }
        return null;
    }

    @Override
    public Date getNullableResult(CallableStatement cs, int columnIndex)
        throws SQLException {
        java.sql.Date sqlDate = cs.getDate(columnIndex);
        if (sqlDate != null) {
            return new Date(sqlDate.getTime());
        }
        return null;
    }

}
EnumTypeHandler
  • org.apache.ibatis.type.EnumTypeHandler ,继承 BaseTypeHandler 抽象类,Enum 类型的 TypeHandler 实现类。
public class EnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {

    // 枚举类型
    private final Class<E> type;

    public EnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        // 将枚举转换为 String 类型
        if (jdbcType == null) {
            ps.setString(i, parameter.name());
        } else {
            ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589
        }
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        // 获得 String 的值
        String s = rs.getString(columnName);
        // 将String转换为Enum类型
        return s == null ? null : Enum.valueOf(type, s);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        // 获得 String 的值
        String s = rs.getString(columnName);
        // 将String转换为Enum类型
        return s == null ? null : Enum.valueOf(type, s);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String s = cs.getString(columnIndex);
        return s == null ? null : Enum.valueOf(type, s);
    }
}
EnumOrdinalTypeHandler
  • org.apache.ibatis.type.EnumOrdinalTypeHandler ,继承 BaseTypeHandler 抽象类,Enum 类型的 TypeHandler 实现类
public class EnumOrdinalTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {

    // 枚举类
    private final Class<E> type;
    // type下的所有的枚举类
    private final E[] enums;

    public EnumOrdinalTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
        this.enums = type.getEnumConstants();
        if (this.enums == null) {
            throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
        }
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        // 将Enum转换为 int 类型
        ps.setInt(i, parameter.ordinal());
    }

    // 下面的方法类似,比较简单不再赘述
    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int ordinal = rs.getInt(columnName);
        if (ordinal == 0 && rs.wasNull()) {
            return null;
        }
        return toOrdinalEnum(ordinal);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int ordinal = rs.getInt(columnIndex);
        if (ordinal == 0 && rs.wasNull()) {
            return null;
        }
        return toOrdinalEnum(ordinal);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int ordinal = cs.getInt(columnIndex);
        if (ordinal == 0 && cs.wasNull()) {
            return null;
        }
        return toOrdinalEnum(ordinal);
    }

    private E toOrdinalEnum(int ordinal) {
        try {
            return enums[ordinal];
        } catch (Exception ex) {
            throw new IllegalArgumentException("Cannot convert " + ordinal + " to " + type.getSimpleName() + " by ordinal value.", ex);
        }
    }
}
ObjectTypeHandler
  • org.apache.ibatis.type.ObjectTypeHandler ,继承 BaseTypeHandler 抽象类,Object 类型的 TypeHandler 实现类
public class ObjectTypeHandler extends BaseTypeHandler<Object> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
        throws SQLException {
        ps.setObject(i, parameter);
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName)
        throws SQLException {
        return rs.getObject(columnName);
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex)
        throws SQLException {
        return rs.getObject(columnIndex);
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex)
        throws SQLException {
        return cs.getObject(columnIndex);
    }
}
UnknownTypeHandler
  • org.apache.ibatis.type.UnknownTypeHandler ,继承 BaseTypeHandler 抽象类,未知的 TypeHandler 实现类。通过获取对应的 TypeHandler ,进行处理
public class UnknownTypeHandler extends BaseTypeHandler<Object> {

    // 单例
    private static final ObjectTypeHandler OBJECT_TYPE_HANDLER = new ObjectTypeHandler();
    // TODO Rename to 'configuration' after removing the 'configuration' property(deprecated property) on parent class
    // 配置
    private final Configuration config;
    // 注册表
    private final Supplier<TypeHandlerRegistry> typeHandlerRegistrySupplier;

    /**
   * The constructor that pass a MyBatis configuration.
   *
   * @param configuration a MyBatis configuration
   * @since 3.5.4
   */
    public UnknownTypeHandler(Configuration configuration) {
        this.config = configuration;
        this.typeHandlerRegistrySupplier = configuration::getTypeHandlerRegistry;
    }

    /**
   * The constructor that pass the type handler registry.
   *
   * @param typeHandlerRegistry a type handler registry
   * @deprecated Since 3.5.4, please use the {@link #UnknownTypeHandler(Configuration)}.
   */
    @Deprecated
    public UnknownTypeHandler(TypeHandlerRegistry typeHandlerRegistry) {
        this.config = new Configuration();
        this.typeHandlerRegistrySupplier = () -> typeHandlerRegistry;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
        throws SQLException {
        // 获得参数对应的处理器
        TypeHandler handler = resolveTypeHandler(parameter, jdbcType);
        // 使用 handler 设置参数
        handler.setParameter(ps, i, parameter, jdbcType);
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName)
        throws SQLException {
        // 获取参数对应的处理器
        TypeHandler<?> handler = resolveTypeHandler(rs, columnName);
        // 使用 handler
        return handler.getResult(rs, columnName);
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex)
        throws SQLException {
        TypeHandler<?> handler = resolveTypeHandler(rs.getMetaData(), columnIndex);
        // 获取不到,使用 OBJECT_TYPE_HANDLER
        if (handler == null || handler instanceof UnknownTypeHandler) {
            handler = OBJECT_TYPE_HANDLER;
        }
        return handler.getResult(rs, columnIndex);
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex)
        throws SQLException {
        return cs.getObject(columnIndex);
    }

    private TypeHandler<?> resolveTypeHandler(Object parameter, JdbcType jdbcType) {
        TypeHandler<?> handler;
        if (parameter == null) {
            handler = OBJECT_TYPE_HANDLER;
        } else {
            handler = typeHandlerRegistrySupplier.get().getTypeHandler(parameter.getClass(), jdbcType);
            // check if handler is null (issue #270)
            if (handler == null || handler instanceof UnknownTypeHandler) {
                handler = OBJECT_TYPE_HANDLER;
            }
        }
        return handler;
    }

    private TypeHandler<?> resolveTypeHandler(ResultSet rs, String column) {
        try {
            Map<String,Integer> columnIndexLookup;
            columnIndexLookup = new HashMap<>();
            ResultSetMetaData rsmd = rs.getMetaData();
            int count = rsmd.getColumnCount();
            boolean useColumnLabel = config.isUseColumnLabel();
            for (int i = 1; i <= count; i++) {
                String name = useColumnLabel ? rsmd.getColumnLabel(i) : rsmd.getColumnName(i);
                columnIndexLookup.put(name,i);
            }
            Integer columnIndex = columnIndexLookup.get(column);
            TypeHandler<?> handler = null;
            if (columnIndex != null) {
                handler = resolveTypeHandler(rsmd, columnIndex);
            }
            if (handler == null || handler instanceof UnknownTypeHandler) {
                handler = OBJECT_TYPE_HANDLER;
            }
            return handler;
        } catch (SQLException e) {
            throw new TypeException("Error determining JDBC type for column " + column + ".  Cause: " + e, e);
        }
    }

    private TypeHandler<?> resolveTypeHandler(ResultSetMetaData rsmd, Integer columnIndex) {
        TypeHandler<?> handler = null;
        JdbcType jdbcType = safeGetJdbcTypeForColumn(rsmd, columnIndex);
        Class<?> javaType = safeGetClassForColumn(rsmd, columnIndex);
        if (javaType != null && jdbcType != null) {
            handler = typeHandlerRegistrySupplier.get().getTypeHandler(javaType, jdbcType);
        } else if (javaType != null) {
            handler = typeHandlerRegistrySupplier.get().getTypeHandler(javaType);
        } else if (jdbcType != null) {
            handler = typeHandlerRegistrySupplier.get().getTypeHandler(jdbcType);
        }
        return handler;
    }

    private JdbcType safeGetJdbcTypeForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
        try {
            return JdbcType.forCode(rsmd.getColumnType(columnIndex));
        } catch (Exception e) {
            return null;
        }
    }

    private Class<?> safeGetClassForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
        try {
            return Resources.classForName(rsmd.getColumnClassName(columnIndex));
        } catch (Exception e) {
            return null;
        }
    }
}

TypeReference

  • org.apache.ibatis.type.TypeReference ,引用泛型抽象类。目的很简单,就是解析类上定义的泛型
public abstract class TypeReference<T> {

    // 泛型
    private final Type rawType;

    protected TypeReference() {
        rawType = getSuperclassTypeParameter(getClass());
    }

    Type getSuperclassTypeParameter(Class<?> clazz) {
        // 从父类中获取泛型
        Type genericSuperclass = clazz.getGenericSuperclass();
        // 满足条件
        if (genericSuperclass instanceof Class) {
            // try to climb up the hierarchy until meet something useful
            if (TypeReference.class != genericSuperclass) {
                return getSuperclassTypeParameter(clazz.getSuperclass());
            }

            throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
                                    + "Remove the extension or add a type parameter to it.");
        }

        // 获取泛型
        Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
        // TODO remove this when Reflector is fixed to return Types
        // 必须是泛型才能拿到
        if (rawType instanceof ParameterizedType) {
            rawType = ((ParameterizedType) rawType).getRawType();
        }

        return rawType;
    }

    public final Type getRawType() {
        return rawType;
    }

    @Override
    public String toString() {
        return rawType.toString();
    }

}

注解

@MappedTypes
  • org.apache.ibatis.type.@MappedTypes ,匹配的 Java Type 类型的注解。
@Documented
@Retention(RetentionPolicy.RUNTIME)
// 注册到类
@Target(ElementType.TYPE)
public @interface MappedTypes {
    /**
   * Returns java types to map {@link TypeHandler}.
   *
   * @return java types
   */
    Class<?>[] value();
}
@MappedJdbcTypes
  • org.apache.ibatis.type.@MappedJdbcTypes ,匹配的 JDBC Type 类型的注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MappedJdbcTypes {
    /**
   * Returns jdbc types to map {@link TypeHandler}.
   * 匹配 JDBC类型
   * @return jdbc types
   */
    JdbcType[] value();

    /**
   * Returns whether map to jdbc null type.
   *
   * @return {@code true} if map, {@code false} if otherwise
   */
    boolean includeNullJdbcType() default false;
}
Alias
  • org.apache.ibatis.type.@Alias ,别名的注解。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Alias {
    /**
   * Return the alias name.
   *
   * @return the alias name 别名
   */
    String value();
}

JdbcType

  • org.apache.ibatis.type.JdbcType ,Jdbc Type 枚举。
public enum JdbcType {
    /*
   * This is added to enable basic support for the
   * ARRAY data type - but a custom type handler is still required
   */
    ARRAY(Types.ARRAY),
    BIT(Types.BIT),
    TINYINT(Types.TINYINT),
    SMALLINT(Types.SMALLINT),
    INTEGER(Types.INTEGER),
    BIGINT(Types.BIGINT),
    FLOAT(Types.FLOAT),
    REAL(Types.REAL),
    DOUBLE(Types.DOUBLE),
    NUMERIC(Types.NUMERIC),
    DECIMAL(Types.DECIMAL),
    CHAR(Types.CHAR),
    VARCHAR(Types.VARCHAR),
    LONGVARCHAR(Types.LONGVARCHAR),
    DATE(Types.DATE),
    TIME(Types.TIME),
    TIMESTAMP(Types.TIMESTAMP),
    BINARY(Types.BINARY),
    VARBINARY(Types.VARBINARY),
    LONGVARBINARY(Types.LONGVARBINARY),
    NULL(Types.NULL),
    OTHER(Types.OTHER),
    BLOB(Types.BLOB),
    CLOB(Types.CLOB),
    BOOLEAN(Types.BOOLEAN),
    CURSOR(-10), // Oracle
    UNDEFINED(Integer.MIN_VALUE + 1000),
    NVARCHAR(Types.NVARCHAR), // JDK6
    NCHAR(Types.NCHAR), // JDK6
    NCLOB(Types.NCLOB), // JDK6
    STRUCT(Types.STRUCT),
    JAVA_OBJECT(Types.JAVA_OBJECT),
    DISTINCT(Types.DISTINCT),
    REF(Types.REF),
    DATALINK(Types.DATALINK),
    ROWID(Types.ROWID), // JDK6
    LONGNVARCHAR(Types.LONGNVARCHAR), // JDK6
    SQLXML(Types.SQLXML), // JDK6
    DATETIMEOFFSET(-155), // SQL Server 2008
    TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE), // JDBC 4.2 JDK8
    TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); // JDBC 4.2 JDK8

    // 类型编号
    public final int TYPE_CODE;
    private static Map<Integer,JdbcType> codeLookup = new HashMap<>();

    static {
        for (JdbcType type : JdbcType.values()) {
            codeLookup.put(type.TYPE_CODE, type);
        }
    }

    JdbcType(int code) {
        this.TYPE_CODE = code;
    }

    public static JdbcType forCode(int code)  {
        return codeLookup.get(code);
    }

}

TypeHandlerRegistry

  • org.apache.ibatis.type.TypeHandlerRegistry ,TypeHandler 注册表,相当于管理 TypeHandler 的容器,从其中能获取到对应的 TypeHandler
// TypeHandlerRegistry.java

/**
 * 空 TypeHandler 集合的标识,即使 {@link #TYPE_HANDLER_MAP} 中,某个 KEY1 对应的 Map<JdbcType, TypeHandler<?>> 为空。
 *
 * @see #getJdbcHandlerMap(Type)
 */
private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();

/**
 * JDBC Type 和 {@link TypeHandler} 的映射
 *
 * {@link #register(JdbcType, TypeHandler)}
 */
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<>(JdbcType.class);
/**
 * {@link TypeHandler} 的映射
 *
 * KEY1:JDBC Type
 * KEY2:Java Type
 * VALUE:{@link TypeHandler} 对象
 */
private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new ConcurrentHashMap<>();
/**
 * 所有 TypeHandler 的“集合”
 *
 * KEY:{@link TypeHandler#getClass()}
 * VALUE:{@link TypeHandler} 对象
 */
private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<>();

/**
 * {@link UnknownTypeHandler} 对象
 */
private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
/**
 * 默认的枚举类型的 TypeHandler 对象
 */
private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;

public TypeHandlerRegistry() {
    // ... 省略其它类型的注册

    // <1>
    register(Date.class, new DateTypeHandler());
    register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
    register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
    // <2>
    register(JdbcType.TIMESTAMP, new DateTypeHandler());
    register(JdbcType.DATE, new DateOnlyTypeHandler());
    register(JdbcType.TIME, new TimeOnlyTypeHandler());

    // ... 省略其它类型的注册
}

// TypeHandlerRegistry.java

public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    // 获得 Class 类型的构造方法
    if (javaTypeClass != null) {
        try {
            Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
            return (TypeHandler<T>) c.newInstance(javaTypeClass); // 符合这个条件的,例如 EnumTypeHandler
        } catch (NoSuchMethodException ignored) {
            // ignored 忽略该异常,继续向下
        } catch (Exception e) {
            throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
        }
    }
    // <2> 获得空参的构造方法
    try {
        Constructor<?> c = typeHandlerClass.getConstructor();
        return (TypeHandler<T>) c.newInstance(); // 符合这个条件的,例如 IntegerTypeHandler
    } catch (Exception e) {
        throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
    }
}

private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
    // <1> 添加 handler 到 TYPE_HANDLER_MAP 中
    if (javaType != null) {
        // 获得 Java Type 对应的 map
        Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
        if (map == null || map == NULL_TYPE_HANDLER_MAP) { // 如果不存在,则进行创建
            map = new HashMap<>();
            TYPE_HANDLER_MAP.put(javaType, map);
        }
        // 添加到 handler 中 map 中
        map.put(jdbcType, handler);
    }
    // <2> 添加 handler 到 ALL_TYPE_HANDLERS_MAP 中
    ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
}

public void register(String packageName) {
    // 扫描指定包下的所有 TypeHandler 类
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
    resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
    Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
    // 遍历 TypeHandler 数组,发起注册
    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);
        }
    }
}

// TypeHandlerRegistry.java

public void register(Class<?> typeHandlerClass) {
    boolean mappedTypeFound = false;
    // <3> 获得 @MappedTypes 注解
    MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
    if (mappedTypes != null) {
        // 遍历注解的 Java Type 数组,逐个进行注册
        for (Class<?> javaTypeClass : mappedTypes.value()) {
            register(javaTypeClass, typeHandlerClass);
            mappedTypeFound = true;
        }
    }
    // <4> 未使用 @MappedTypes 注解,则直接注册
    if (!mappedTypeFound) {
        register(getInstance(null, typeHandlerClass)); // 创建 TypeHandler 对象
    }
}

public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass)); // 创建 TypeHandler 对象
}

// TypeHandlerRegistry.java

private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
    // 获得 MappedJdbcTypes 注解
    MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
    if (mappedJdbcTypes != null) {
        // 遍历 MappedJdbcTypes 注册的 JDBC Type 进行注册
        for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
            register(javaType, handledJdbcType, typeHandler);
        }
        if (mappedJdbcTypes.includeNullJdbcType()) {
            // <5>
            register(javaType, null, typeHandler); // jdbcType = null
        }
    } else {
        // <5>
        register(javaType, null, typeHandler); // jdbcType = null
    }
}

// TypeHandlerRegistry.java

public <T> void register(TypeHandler<T> typeHandler) {
    boolean mappedTypeFound = false;
    // <5> 获得 @MappedTypes 注解
    MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class);
    // 优先,使用 @MappedTypes 注解的 Java Type 进行注册
    if (mappedTypes != null) {
        for (Class<?> handledType : mappedTypes.value()) {
            register(handledType, typeHandler);
            mappedTypeFound = true;
        }
    }
    // @since 3.1.0 - try to auto-discover the mapped type
    // <6> 其次,当 typeHandler 为 TypeReference 子类时,进行注册
    if (!mappedTypeFound && typeHandler instanceof TypeReference) {
        try {
            TypeReference<T> typeReference = (TypeReference<T>) typeHandler;
            register(typeReference.getRawType(), typeHandler); // Java Type 为 <T> 泛型
            mappedTypeFound = true;
        } catch (Throwable t) {
            // maybe users define the TypeReference with a different type and are not assignable, so just ignore it
        }
    }
    // <7> 最差,使用 Java Type 为 null 进行注册
    if (!mappedTypeFound) {
        register((Class<T>) null, typeHandler);
    }
}

// TypeHandlerRegistry.java

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

private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
    // 忽略 ParamMap 的情况
    if (ParamMap.class.equals(type)) {
        return null;
    }
    // <1> 获得 Java Type 对应的 TypeHandler 集合
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);
    TypeHandler<?> handler = null;
    if (jdbcHandlerMap != null) {
        // <2.1> 优先,使用 jdbcType 获取对应的 TypeHandler
        handler = jdbcHandlerMap.get(jdbcType);
        // <2.2> 其次,使用 null 获取对应的 TypeHandler ,可以认为是默认的 TypeHandler
        if (handler == null) {
            handler = jdbcHandlerMap.get(null);
        }
        // <2.3> 最差,从 TypeHandler 集合中选择一个唯一的 TypeHandler
        if (handler == null) {
            // #591
            handler = pickSoleHandler(jdbcHandlerMap);
        }
    }
    // type drives generics here
    return (TypeHandler<T>) handler;
}

private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMap(Type type) {
    // <1.1> 获得 Java Type 对应的 TypeHandler 集合
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);
    // <1.2> 如果为 NULL_TYPE_HANDLER_MAP ,意味着为空,直接返回
    if (NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap)) {
        return null;
    }
    // <1.3> 如果找不到
    if (jdbcHandlerMap == null && type instanceof Class) {
        Class<?> clazz = (Class<?>) type;
        // 枚举类型
        if (clazz.isEnum()) {
            // 获得父类对应的 TypeHandler 集合
            jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(clazz, clazz);
            // 如果找不到
            if (jdbcHandlerMap == null) {
                // 注册 defaultEnumTypeHandler ,并使用它
                register(clazz, getInstance(clazz, defaultEnumTypeHandler));
                // 返回结果
                return TYPE_HANDLER_MAP.get(clazz);
            }
            // 非枚举类型
        } else {
            // 获得父类对应的 TypeHandler 集合
            jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz);
        }
    }
    // <1.4> 如果结果为空,设置为 NULL_TYPE_HANDLER_MAP ,提升查找速度,避免二次查找
    TYPE_HANDLER_MAP.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap);
    // 返回结果
    return jdbcHandlerMap;
}

private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMapForEnumInterfaces(Class<?> clazz, Class<?> enumClazz) {
    // 遍历枚举类的所有接口
    for (Class<?> iface : clazz.getInterfaces()) {
        // 获得该接口对应的 jdbcHandlerMap 集合
        Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(iface);
        // 为空,递归 getJdbcHandlerMapForEnumInterfaces 方法,继续从父类对应的 TypeHandler 集合
        if (jdbcHandlerMap == null) {
            jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(iface, enumClazz);
        }
        // 如果找到,则从 jdbcHandlerMap 初始化中 newMap 中,并进行返回
        if (jdbcHandlerMap != null) {
            // Found a type handler regsiterd to a super interface
            HashMap<JdbcType, TypeHandler<?>> newMap = new HashMap<>();
            for (Entry<JdbcType, TypeHandler<?>> entry : jdbcHandlerMap.entrySet()) {
                // Create a type handler instance with enum type as a constructor arg
                newMap.put(entry.getKey(), getInstance(enumClazz, entry.getValue().getClass()));
            }
            return newMap;
        }
    }
    // 找不到,则返回 null
    return null;
}

// TypeHandlerRegistry.java

private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMapForSuperclass(Class<?> clazz) {
    // 获得父类
    Class<?> superclass = clazz.getSuperclass();
    // 不存在非 Object 的父类,返回 null
    if (superclass == null || Object.class.equals(superclass)) {
        return null;
    }
    // 获得父类对应的 TypeHandler 集合
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(superclass);
    // 找到,则直接返回
    if (jdbcHandlerMap != null) {
        return jdbcHandlerMap;
        // 找不到,则递归 getJdbcHandlerMapForSuperclass 方法,继续获得父类对应的 TypeHandler 集合
    } else {
        return getJdbcHandlerMapForSuperclass(superclass);
    }
}

private TypeHandler<?> pickSoleHandler(Map<JdbcType, TypeHandler<?>> jdbcHandlerMap) {
    TypeHandler<?> soleHandler = null;
    for (TypeHandler<?> handler : jdbcHandlerMap.values()) {
        // 选择一个
        if (soleHandler == null) {
            soleHandler = handler;
        // 如果还有,并且不同类,那么不好选择,所以返回 null
        } else if (!handler.getClass().equals(soleHandler.getClass())) {
            // More than one type handlers registered.
            return null;
        }
    }
    return soleHandler;
}

TypeAliasRegistry

  • org.apache.ibatis.type.TypeAliasRegistry ,类型与别名的注册表。通过别名,我们在 Mapper XML 中的 resultTypeparameterType 属性,直接使用,而不用写全类名。
public class TypeAliasRegistry {

    // 类型与别名的映射
    private final Map<String, Class<?>> typeAliases = new HashMap<>();

    public TypeAliasRegistry() {
        registerAlias("string", String.class);

        registerAlias("byte", Byte.class);
        registerAlias("long", Long.class);
        registerAlias("short", Short.class);
        registerAlias("int", Integer.class);
        registerAlias("integer", Integer.class);
        registerAlias("double", Double.class);
        registerAlias("float", Float.class);
        registerAlias("boolean", Boolean.class);

        registerAlias("byte[]", Byte[].class);
        registerAlias("long[]", Long[].class);
        registerAlias("short[]", Short[].class);
        registerAlias("int[]", Integer[].class);
        registerAlias("integer[]", Integer[].class);
        registerAlias("double[]", Double[].class);
        registerAlias("float[]", Float[].class);
        registerAlias("boolean[]", Boolean[].class);

        registerAlias("_byte", byte.class);
        registerAlias("_long", long.class);
        registerAlias("_short", short.class);
        registerAlias("_int", int.class);
        registerAlias("_integer", int.class);
        registerAlias("_double", double.class);
        registerAlias("_float", float.class);
        registerAlias("_boolean", boolean.class);

        registerAlias("_byte[]", byte[].class);
        registerAlias("_long[]", long[].class);
        registerAlias("_short[]", short[].class);
        registerAlias("_int[]", int[].class);
        registerAlias("_integer[]", int[].class);
        registerAlias("_double[]", double[].class);
        registerAlias("_float[]", float[].class);
        registerAlias("_boolean[]", boolean[].class);

        registerAlias("date", Date.class);
        registerAlias("decimal", BigDecimal.class);
        registerAlias("bigdecimal", BigDecimal.class);
        registerAlias("biginteger", BigInteger.class);
        registerAlias("object", Object.class);

        registerAlias("date[]", Date[].class);
        registerAlias("decimal[]", BigDecimal[].class);
        registerAlias("bigdecimal[]", BigDecimal[].class);
        registerAlias("biginteger[]", BigInteger[].class);
        registerAlias("object[]", Object[].class);

        registerAlias("map", Map.class);
        registerAlias("hashmap", HashMap.class);
        registerAlias("list", List.class);
        registerAlias("arraylist", ArrayList.class);
        registerAlias("collection", Collection.class);
        registerAlias("iterator", Iterator.class);

        registerAlias("ResultSet", ResultSet.class);
    }

    @SuppressWarnings("unchecked")
    // throws class cast exception as well if types cannot be assigned
    public <T> Class<T> resolveAlias(String string) {
        try {
            if (string == null) {
                return null;
            }
            // issue #748
            String key = string.toLowerCase(Locale.ENGLISH);
            Class<T> value;
            if (typeAliases.containsKey(key)) {
                value = (Class<T>) typeAliases.get(key);
            } else {
                value = (Class<T>) Resources.classForName(string);
            }
            return value;
        } catch (ClassNotFoundException e) {
            throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);
        }
    }

    // 注册包的类
    public void registerAliases(String packageName) {
        registerAliases(packageName, Object.class);
    }

    // 注册类
    public void registerAliases(String packageName, Class<?> superType) {
        ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
        resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
        Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
        for (Class<?> type : typeSet) {
            // Ignore inner classes and interfaces (including package-info.java)
            // Skip also inner classes. See issue #6
            if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
                registerAlias(type);
            }
        }
    }

    // 注册指定类
    public void registerAlias(Class<?> type) {
        String alias = type.getSimpleName();
        Alias aliasAnnotation = type.getAnnotation(Alias.class);
        if (aliasAnnotation != null) {
            alias = aliasAnnotation.value();
        }
        registerAlias(alias, type);
    }

    public void registerAlias(String alias, Class<?> value) {
        if (alias == null) {
            throw new TypeException("The parameter alias cannot be null");
        }
        // issue #748
        String key = alias.toLowerCase(Locale.ENGLISH);
        if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
            throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
        }
        typeAliases.put(key, value);
    }

    public void registerAlias(String alias, String value) {
        try {
            registerAlias(alias, Resources.classForName(value));
        } catch (ClassNotFoundException e) {
            throw new TypeException("Error registering type alias " + alias + " for " + value + ". Cause: " + e, e);
        }
    }

    /**
   * Gets the type aliases.
   *
   * @return the type aliases
   * @since 3.2.2
   */
    public Map<String, Class<?>> getTypeAliases() {
        return Collections.unmodifiableMap(typeAliases);
    }

}

SimpleTypeRegistry

  • org.apache.ibatis.type.SimpleTypeRegistry ,简单类型注册表
public class SimpleTypeRegistry {

    // 简单类型集合
    private static final Set<Class<?>> SIMPLE_TYPE_SET = new HashSet<>();

    // 初始化
    static {
        SIMPLE_TYPE_SET.add(String.class);
        SIMPLE_TYPE_SET.add(Byte.class);
        SIMPLE_TYPE_SET.add(Short.class);
        SIMPLE_TYPE_SET.add(Character.class);
        SIMPLE_TYPE_SET.add(Integer.class);
        SIMPLE_TYPE_SET.add(Long.class);
        SIMPLE_TYPE_SET.add(Float.class);
        SIMPLE_TYPE_SET.add(Double.class);
        SIMPLE_TYPE_SET.add(Boolean.class);
        SIMPLE_TYPE_SET.add(Date.class);
        SIMPLE_TYPE_SET.add(Class.class);
        SIMPLE_TYPE_SET.add(BigInteger.class);
        SIMPLE_TYPE_SET.add(BigDecimal.class);
    }

    private SimpleTypeRegistry() {
        // Prevent Instantiation
    }

    /*
   * Tells us if the class passed in is a known common type
   *
   * @param clazz The class to check
   * @return True if the class is known
   */
    public static boolean isSimpleType(Class<?> clazz) {
        return SIMPLE_TYPE_SET.contains(clazz);
    }

}
1
https://gitee.com/elonchung/Java-Review.git
git@gitee.com:elonchung/Java-Review.git
elonchung
Java-Review
Java-Review
master

搜索帮助