Mybatis-TypeHandler源码解析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

TypeHandler

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 类型处理器
 * 

* 无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, * 都会用类型处理器将获取的值以合适的方式转换成 Java 类型 *

* * @author Clinton Begin */ public interface TypeHandler { /** * 把 java 对象设置到 PreparedStatement 的参数中 * @param i 从1开始 */ void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; /** * 从 ResultSet 中取出columnName对应数据,然后转换为 java 对象 * @param columnName Colunm name, when configuration useColumnLabel is false */ T getResult(ResultSet rs, String columnName) throws SQLException; /** * 用于从 ResultSet 或 CallableStatement 中取出数据转换为 java 对象 */ T getResult(ResultSet rs, int columnIndex) throws SQLException; /** * 用于从 ResultSet 或 CallableStatement 中取出数据转换为 java 对象 */ T getResult(CallableStatement cs, int columnIndex) throws SQLException; }

BaseTypeHandler

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.executor.result.ResultMapException;
import org.apache.ibatis.session.Configuration;

/**
 * The base {@link TypeHandler} for references a generic type.
 * 一个基本的{@link TypeHandler}引用了一个泛型类型
 * 

* Important: Since 3.5.0, This class never call the {@link ResultSet#wasNull()} and * {@link CallableStatement#wasNull()} method for handling the SQL {@code NULL} value. * In other words, {@code null} value handling should be performed on subclass. *

*

* 重点声明:自从3.5.0后,这个类不会再调用{@link ResultSet#wasNull()}和{@link CallableStatement#wasNull()} * 方法去处理null值的,换句话说,null值应该交给子类处理。 *

* @author Clinton Begin * @author Simone Tripodi * @author Kzuki Shimizu */ public abstract class BaseTypeHandler extends TypeReference implements TypeHandler { /** * @deprecated Since 3.5.0 - See https://github.com/mybatis/mybatis-3/issues/1203. This field will remove future. */ @Deprecated protected Configuration configuration; /** * @deprecated Since 3.5.0 - See https://github.com/mybatis/mybatis-3/issues/1203. This property will remove future. */ @Deprecated public void setConfiguration(Configuration c) { this.configuration = c; } /** * 把 java 对象设置到 PreparedStatement 的参数中 *

* 解决 {@link @paramter} ,{@link @jdbcType} 的情况。 *

*
    *
  1. {@link @jdbcType}为null,抛出 {@link TypeException},也就是说{@link @jdbcType}调用这个方法的时候就已经确定了
  2. *
  3. {@link @parameter}为null时,对第{@link @i}个'?'设置null值;否则, * 调用抽象方法{@link BaseTypeHandler#setNonNullParameter(PreparedStatement, int, Object, JdbcType)}
  4. *
*/ @Override public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { //一般情况下,jdbcType到这个方法时就已经确定了jdbcType.TYPE_CODE, 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); } } } /** * 用于从 ResultSet 或 CallableStatement 中取出数据转换为 java 对象 *

* 直接调用{@link BaseTypeHandler#getNullableResult(ResultSet, String)} *

*/ @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); } } /** * 用于从 ResultSet 或 CallableStatement 中取出数据转换为 java 对象 *

* 直接调用{@link BaseTypeHandler#getNullableResult(ResultSet, int)} *

*/ @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); } } /** * 用于从 ResultSet 或 CallableStatement 中取出数据转换为 java 对象 *

* 直接调用{@link BaseTypeHandler#getNullableResult(CallableStatement, int)} *

*/ @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; /** * 获取可空的结果 * @param columnName Colunm name, when configuration useColumnLabel is false */ 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; }

ObjectTypeHandler

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Object 类型处理器
 * @author Clinton Begin
 */
public class ObjectTypeHandler extends BaseTypeHandler {

  /**
   * 直接调用 {@link PreparedStatement#setObject(int, Object)}
   */
  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setObject(i, parameter);
  }

  /**
   * 直接调用 {@link ResultSet#getObject(String)}
   */
  @Override
  public Object getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    return rs.getObject(columnName);
  }

  /**
   * 直接调用 {@link ResultSet#getObject(int)}
   */
  @Override
  public Object getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {
    return rs.getObject(columnIndex);
  }

  /**
   * 直接调用 {@link CallableStatement#getObject(int)}
   */
  @Override
  public Object getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {
    return cs.getObject(columnIndex);
  }
}

 
 

UnknowTypeHandler

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.io.Resources;

/**
 * 未知类型处理器
 * 

在{@link BaseTypeHandler}的抽象方法中根据返回的结果集提供的列去获取对应的TypeHandler时候, * 在获取不到的情况下,就会使用{@link ObjectTypeHandler}处理

* @author Clinton Begin */ public class UnknownTypeHandler extends BaseTypeHandler { private static final ObjectTypeHandler OBJECT_TYPE_HANDLER = new ObjectTypeHandler(); private TypeHandlerRegistry typeHandlerRegistry; public UnknownTypeHandler(TypeHandlerRegistry typeHandlerRegistry) { this.typeHandlerRegistry = typeHandlerRegistry; } @Override public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { TypeHandler handler = resolveTypeHandler(parameter, jdbcType); handler.setParameter(ps, i, parameter, jdbcType); } @Override public Object getNullableResult(ResultSet rs, String columnName) throws SQLException { TypeHandler handler = resolveTypeHandler(rs, columnName); return handler.getResult(rs, columnName); } @Override public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException { TypeHandler handler = resolveTypeHandler(rs.getMetaData(), columnIndex); 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); } /** * 解析获取类型处理器 *

根据 {@code parameter} 和 {@code jdbcType} 获取typeHandler实例

* @return {@code parameter} 为null 或者 * 获取不了对应{@code parameter} 和 {@code jdbcType} 的typeHanlder实例 * 或者为typeHandler实例都为{@link UnknownTypeHandler}的实例的话,都会返回{@link #OBJECT_TYPE_HANDLER} */ private TypeHandler resolveTypeHandler(Object parameter, JdbcType jdbcType) { TypeHandler handler; if (parameter == null) { handler = OBJECT_TYPE_HANDLER; } else { //获取typeHandler实例 handler = typeHandlerRegistry.getTypeHandler(parameter.getClass(), jdbcType); // check if handler is null (issue #270) if (handler == null || handler instanceof UnknownTypeHandler) { handler = OBJECT_TYPE_HANDLER; } } return handler; } /** * 解析获取TypeHandler实例 *

* 通过{@code rs}拿到结果集的描述信息{@link ResultSetMetaData},根据描述信息去拿到列名对应的 * 位置,再调用{@link #resolveTypeHandler(ResultSetMetaData, Integer)}获取对应的TypeHandler实例。 *

* @param rs 结果集 * @param column 列名 * @return {@link TypeHandler} 实例; * 当 {@code handler} 为null或者 {@code handler} 为 {@link UnknownTypeHandler} 就会返回 {@link #OBJECT_TYPE_HANDLER} */ private TypeHandler resolveTypeHandler(ResultSet rs, String column) { try { //将所有列的列名,对应的位置都拿出来放到columnIndexLookup中 Map columnIndexLookup; columnIndexLookup = new HashMap<>(); ResultSetMetaData rsmd = rs.getMetaData(); int count = rsmd.getColumnCount(); for (int i = 1; i <= count; i++) { String name = rsmd.getColumnName(i); columnIndexLookup.put(name,i); } //拿到column对应的位置 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); } } /** * 解析获取TypeHandler实例 * @param rsmd 结果集描述信息 * @param columnIndex 指定的列位置 * @return TypeHandler实例 */ private TypeHandler resolveTypeHandler(ResultSetMetaData rsmd, Integer columnIndex) { TypeHandler handler = null; //从columnIndex中获取jdbcType,不会抛出异常,但是会返回null JdbcType jdbcType = safeGetJdbcTypeForColumn(rsmd, columnIndex); //从columnIndex中获取javaType,不会抛出异常,但是会返回null Class javaType = safeGetClassForColumn(rsmd, columnIndex); //根据现有的条件,尽可能的找到对应的typeHandler实例 if (javaType != null && jdbcType != null) { handler = typeHandlerRegistry.getTypeHandler(javaType, jdbcType); } else if (javaType != null) { handler = typeHandlerRegistry.getTypeHandler(javaType); } else if (jdbcType != null) { handler = typeHandlerRegistry.getTypeHandler(jdbcType); } return handler; } /** * 安全的从列中拿到jdbcType,这里的安全应该是指捕捉的所有获取过程中抛出的异常。 * @param rsmd 结果集的描述信息 * @param columnIndex 指定的列位置 * @return {@link JdbcType},在获取过程中抛出异常会返回 {@code null} */ private JdbcType safeGetJdbcTypeForColumn(ResultSetMetaData rsmd, Integer columnIndex) { try { return JdbcType.forCode(rsmd.getColumnType(columnIndex)); } catch (Exception e) { return null; } } /** * 安全的从列中拿到javaType,这里的安全应该是指捕捉的所有获取过程中抛出的异常。 * @param rsmd 结果集的描述信息 * @param columnIndex 指定的列位置 * @return {@link Class},在获取过程中抛出异常会返回 {@code null} */ private Class safeGetClassForColumn(ResultSetMetaData rsmd, Integer columnIndex) { try { return Resources.classForName(rsmd.getColumnClassName(columnIndex)); } catch (Exception e) { return null; } } }

TypeHandlerRegistry

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZonedDateTime;
import java.time.chrono.JapaneseDate;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.io.Resources;

/**
 * 类型处理注册器
 *
 * 
* 参考博客: *
    *
  1. https://www.jianshu.com/p/93f6205fb0ba
  2. *
  3. https://www.jianshu.com/p/44d01981d698
  4. *
* @author Clinton Begin * @author Kazuki Shimizu */ public final class TypeHandlerRegistry { /** * 枚举类JdbcType作为键,完成数据库类型与类型处理器的对应注册 */ private final Map> jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class); /** * Java类型作为键,JdbcType与TypeHandler的映射关系作为value,完成Java类型、数据库类型和类型处理器三者的对应注册 */ private final Map>> typeHandlerMap = new ConcurrentHashMap<>(); /** * 对未知类型的注册,如Object * 其实还是在{@link BaseTypeHandler}的抽象方法中根据返回的结果集提供的列去获取对应的TypeHandler时候, * 在获取不到的情况下,就会使用{@link ObjectTypeHandler}处理 */ private final TypeHandler unknownTypeHandler = new UnknownTypeHandler(this); /** * 保存着所有的类型处理器实例,是以类型处理器的类类型为键值保存的,它可以统筹所有的类型处理器实例 */ private final Map, TypeHandler> allTypeHandlersMap = new HashMap<>(); /** * 空TypeHandler集合的标识 */ private static final Map> NULL_TYPE_HANDLER_MAP = Collections.emptyMap(); /** * 默认的枚举类型 */ private Class defaultEnumTypeHandler = EnumTypeHandler.class; /** * 注册一些基本的,常用的TypeHandler */ 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 StringTypeHandler()); 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 StringTypeHandler()); 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, unknownTypeHandler); register(Object.class, JdbcType.OTHER, unknownTypeHandler); register(JdbcType.OTHER, unknownTypeHandler); 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()); register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler()); register(Instant.class, new InstantTypeHandler()); register(LocalDateTime.class, new LocalDateTimeTypeHandler()); register(LocalDate.class, new LocalDateTypeHandler()); register(LocalTime.class, new LocalTimeTypeHandler()); register(OffsetDateTime.class, new OffsetDateTimeTypeHandler()); register(OffsetTime.class, new OffsetTimeTypeHandler()); register(ZonedDateTime.class, new ZonedDateTimeTypeHandler()); register(Month.class, new MonthTypeHandler()); register(Year.class, new YearTypeHandler()); register(YearMonth.class, new YearMonthTypeHandler()); register(JapaneseDate.class, new JapaneseDateTypeHandler()); // issue #273 register(Character.class, new CharacterTypeHandler()); register(char.class, new CharacterTypeHandler()); } /** * Set a default {@link TypeHandler} class for {@link Enum}. * A default {@link TypeHandler} is {@link org.apache.ibatis.type.EnumTypeHandler}. *

* 为枚举类{@link Enum}设置默认的{@link TypeHandler}.默认是{@link EnumTypeHandler} *

* @param typeHandler a type handler class for {@link Enum} * @since 3.4.5 */ public void setDefaultEnumTypeHandler(Class typeHandler) { this.defaultEnumTypeHandler = typeHandler; } /** * 是否存在对应 {@link @javaType} 的 {@link TypeHandler},直接调用{@link #hasTypeHandler(Class, JdbcType)} */ public boolean hasTypeHandler(Class javaType) { return hasTypeHandler(javaType, null); } /** * 是否存在对应{@link @javaTypeReference}的{@link TypeHandler},直接调用{@link #hasTypeHandler(TypeReference, JdbcType)}, * 第二个参数{@link @jdbcType}为null */ public boolean hasTypeHandler(TypeReference javaTypeReference) { return hasTypeHandler(javaTypeReference, null); } /** * 是否存在对应 {@link @javaType} 和 {@link @jdbcType} 的 {@link TypeHandler} *

* 先判断{@link @javaType} 是否为null,若为null,直接返回false。 * 再尝试调用{@link #getTypeHandler(Type, JdbcType)}获取TypeHandler不为null返回true *

*/ public boolean hasTypeHandler(Class javaType, JdbcType jdbcType) { return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null; } /** * 是否存在对应 {@link @javaTypeReference} 和 {@link @jdbcType} 的 {@link TypeHandler} *

* 先判断{@link @javaTypeReference} 是否为null,若为null,直接返回false。 * 再尝试调用{@link #getTypeHandler(TypeReference, JdbcType)}获取TypeHandler不为null返回true *

*/ public boolean hasTypeHandler(TypeReference javaTypeReference, JdbcType jdbcType) { return javaTypeReference != null && getTypeHandler(javaTypeReference, jdbcType) != null; } /** * 获取TypeHandler实例 *

* 从{@link #allTypeHandlersMap} 中获取对应{@link @handlerType}的{@link @handlerType}实例 *

*/ public TypeHandler getMappingTypeHandler(Class> handlerType) { return allTypeHandlersMap.get(handlerType); } /** * 获取TypeHandler实例 *

* 将{@link @type}强转为{@link Type},然后调用{@link #getTypeHandler(Type, JdbcType)},第二个参数{@link @jdbcType}设置成null *

*/ public TypeHandler getTypeHandler(Class type) { return getTypeHandler((Type) type, null); } /** * 获取TypeHandler实例 *

* 直接调用{@link #getTypeHandler(TypeReference, JdbcType)},第二个参数{@link @jdbcType}设置成null *

*/ public TypeHandler getTypeHandler(TypeReference javaTypeReference) { return getTypeHandler(javaTypeReference, null); } /** * 获取TypeHandler实例 *

* 从{@link #jdbcTypeHandlerMap}中获取对应{@link @jdbcType} *

*/ public TypeHandler getTypeHandler(JdbcType jdbcType) { return jdbcTypeHandlerMap.get(jdbcType); } /** * 获取 TypeHandler *

* 将 {@link @type} 转换 {@link Type} 类型,然后调用 {@link TypeHandlerRegistry#getTypeHandler(Class, JdbcType)} *

*/ public TypeHandler getTypeHandler(Class type, JdbcType jdbcType) { return getTypeHandler((Type) type, jdbcType); } /** * 获取 TypeHandler *

* 调用{@link @javaTypeReference}的{@link TypeReference#getRawType()}得到子类声明的对 T 泛型的声明的类型, * 然后传给{@link #getTypeHandler(Type, JdbcType)}得到对应的TypeHandler *

*/ public TypeHandler getTypeHandler(TypeReference javaTypeReference, JdbcType jdbcType) { return getTypeHandler(javaTypeReference.getRawType(), jdbcType); } /** * 根据 {@link @type} 和 {@link @jdbcType} 获取对应的 {@link TypeHandler} *
    *
  1. 如果{@link @type}是{@link ParamMap}会直接返回null
  2. *
  3. 通过{@link #getJdbcHandlerMap(Type)}获取dbcType、TypeHandler映射关系的map并赋值给{@link @jdbcHandlerMap}
  4. *
  5. 传入{@link @jdbcType}到{@link @jdbcHandlerMap}中获取对应的TypeHandler并赋值给{@link @handler}
  6. *
  7. 如果{@link @handler}为null,就是没有拿到对应的TypeHandler,就会从{@link @jdbcHandlerMap}取出对应'null'的TypeHandler
  8. *
  9. 如果{@link @handler}还为null,将{@link @jdbcHandlerMap}传入{@link #pickSoleHandler(Map)},由Mybatis自己选择一个TypeHandler
  10. *
  11. 如果{@link @handler}还为null,就等于没救了,返回null
  12. *
*/ @SuppressWarnings("unchecked") private TypeHandler getTypeHandler(Type type, JdbcType jdbcType) { //{@link ParamMap)是一个HashMap的子类,它重写了get方法,使得如果尝试获取它没有的key,将会抛出{@link BindingException} if (ParamMap.class.equals(type)) { return null; } //获取JdbcType、TypeHandler映射关系的map Map> jdbcHandlerMap = getJdbcHandlerMap(type); TypeHandler handler = null; if (jdbcHandlerMap != null) { handler = jdbcHandlerMap.get(jdbcType);//获取对应jdbcType的TypeHandler //如果没有拿到,调用获取jdbcType为null值情况的TypeHandler if (handler == null) { handler = jdbcHandlerMap.get(null); } /** * 还是没有拿到,就由Mybatis自己选择一个TypeHandler: * 如果有多个不同类型的TypeHandler就无法选择TypeHandler,只能返回null; * 但是如果只有一个类型的TypeHandler,但有多个同类型的TypeHandler实例,就取最后一个实例 */ if (handler == null) { // #591 handler = pickSoleHandler(jdbcHandlerMap); } } // type drives generics here //就算handler=null,也不会抛出空指针或者转换异常 return (TypeHandler) handler; } /** * 获取JdbcType、TypeHandler映射关系的map *

* 先将{@link @type}传入从{@link #typeHandlerMap}中获取JdbcType、TypeHandler映射关系的map。如果找到就返回出去。 * 如果没有获取到,判断是不是枚举类,还是普通java类。 * *

*

* 枚举类: *

    *
  1. 调用{@link #getJdbcHandlerMapForEnumInterfaces(Class, Class)} 遍历枚举类的接口获取第一个对应 * {@link @type}的JdbcType、TypeHandler映射关系的map
  2. *
  3. 若还是找不到,就构建{@link #defaultEnumTypeHandler}的实例,作为{@link @clazz} * 对应的JdbcType、TypeHandler映射关系的map设置到{@link #typeHandlerMap}, * 然后重新到{@link #typeHandlerMap}返回出去,其实返回出去的按理来说就是{@link #defaultEnumTypeHandler}的实例
  4. *
  5. 找到就设置到{@link #typeHandlerMap}中,并返回对应的JdbcType、TypeHandler映射关系的map
  6. *
*

*

* 普通java类: *

    *
  1. 将{@link @type}传入{@link #getJdbcHandlerMapForSuperclass}方法,遍历父类获取第一个对应 * {@link @type}的JdbcType、TypeHandler映射关系的map
  2. *
  3. 若还是没有找到,就直接将{@link #NULL_TYPE_HANDLER_MAP}作为对应{@link @type}的JdbcType、TypeHandler映射关系的map。 * 然后返回null
  4. *
  5. 找到就设置到{@link #typeHandlerMap}中,并返回对应的JdbcType、TypeHandler映射关系的map
  6. *
*

*/ private Map> getJdbcHandlerMap(Type type) { Map> jdbcHandlerMap = typeHandlerMap.get(type); if (NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap)) {//空TypeHandler标识返回null也是符合场景的。 return null; } //没有找到该类的JdbcType、TypeHandler映射关系Map 而且 {@link @type} 是 Class类, if (jdbcHandlerMap == null && type instanceof Class) { Class clazz = (Class) type; if (Enum.class.isAssignableFrom(clazz)) {//属于枚举类型 //clazz若是枚举类型,clazz.getSuperclass()就得到java.lang.Enum,因为枚举类型不能extends,但是可以implement //下面代码如果属于内部类,就会得到java.lang.Enum Class enumClass = clazz.isAnonymousClass() ? clazz.getSuperclass() : clazz; //从枚举类的接口获取JdbcType、TypeHandler映射关系的map jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(enumClass, enumClass); //还是没有找到的话,就用defaultEnumTypeHandler的实例对象作为对应enumClass的TypeHandler if (jdbcHandlerMap == null) { register(enumClass, getInstance(enumClass, defaultEnumTypeHandler)); return typeHandlerMap.get(enumClass); } } else { //尝试通过获取父类去获取JdbcType、TypeHandler映射关系Map jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz); } } //没有JdbcType、TypeHandler映射关系Map时,就用NULL_TYPE_HANDLER_MAP作为对应type的JdbcType、TypeHandler映射关系Map typeHandlerMap.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap); return jdbcHandlerMap; } /** * 从枚举类的接口获取JdbcType、TypeHandler映射关系的map *

* 通过递归该方法深入{@link @clazz}的所有接口,若找到{@link @clazz}接口对应的JdbcType、TypeHandler映射关系map【{@link @jdbcHandlerMap}】, * 就会根据{@link @jdbcHandlerMap}构建出{@link @enumClazz}对应的JdbcType、TypeHandler映射关系map。注意一下, * 只会找出第一个匹配的JdbcType、TypeHandler映射关系map赋值给{@link @jdbcHandlerMap}。若还是没有找到JdbcType、TypeHandler映射关系map, * 就会返回null *

*/ private Map> getJdbcHandlerMapForEnumInterfaces(Class clazz, Class enumClazz) { for (Class iface : clazz.getInterfaces()) {//获取该枚举类所实现的所有接口 //尝试通过接口类获取JdbcType、TypeHandler映射关系的map Map> jdbcHandlerMap = typeHandlerMap.get(iface); //如果还是没有找到,通过递归的方式,深入这个接口中看看还有没有继承接口,从那些接口里尝试获取JdbcType、TypeHandler映射关系的map if (jdbcHandlerMap == null) { jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(iface, enumClazz); } //找到了与接口对应的JdbcType、TypeHandler映射关系map后 if (jdbcHandlerMap != null) { // Found a type handler regsiterd to a super interface //构建一个新的JdbcType、TypeHandler映射关系map HashMap> newMap = new HashMap<>(); /** * 将jdbcHandlerMap的元素添加给newMap: * 将jdbcHandlerMap的key作为newMap的key, * 传入enumClazz以及通过jdbcHandlerMap的value获取value的Class来构建一个对应该枚举类的TypeHandler对象作为value */ for (Entry> entry : jdbcHandlerMap.entrySet()) { // Create a type handler instance with enum type as a constructor arg newMap.put(entry.getKey(), getInstance(enumClazz, entry.getValue().getClass())); } /** * 在这里进行方法返回,就说明该方法只会找出第一个匹配的JdbcType、TypeHandler映射关系map, * 就算真的有两个匹配的JdbcType、TypeHandler映射关系map,也不会合并且其JdbcType、TypeHandler映射关系map */ return newMap; } } return null;//实在没有找到的话,返回null,也是很合理的。 } /** * 通过获取父类去获取JdbcType、TypeHandler映射关系Map *

* 通过递归{@link @clazz}的父类,获取第一个对应父类的JdbcType、TypeHandler映射关系Map *

*/ private Map> getJdbcHandlerMapForSuperclass(Class clazz) { Class superclass = clazz.getSuperclass(); /** * 没有获取到父类 或者 递归父类去获取JdbcType、TypeHandler映射关系Map,都到了Object,返回null也是理所当然啦 */ if (superclass == null || Object.class.equals(superclass)) { return null; } Map> jdbcHandlerMap = typeHandlerMap.get(superclass); if (jdbcHandlerMap != null) { /** * 只会找出第一个匹配的JdbcType、TypeHandler映射关系map, * 就算真的有两个匹配的JdbcType、TypeHandler映射关系map,也不会合并且其JdbcType、TypeHandler映射关系map */ return jdbcHandlerMap; } else { //递归父类 return getJdbcHandlerMapForSuperclass(superclass); } } /** * 取唯一的TypeHandler *

* 如果有多个不同类型的TypeHandler就无法选择TypeHandler,只能返回null; * 但是如果只有一个类型的TypeHandler,但有多个同类型的TypeHandler实例,就取最后一个实例 *

* @param jdbcHandlerMap * @return */ private TypeHandler pickSoleHandler(Map> jdbcHandlerMap) { TypeHandler soleHandler = null; for (TypeHandler handler : jdbcHandlerMap.values()) { if (soleHandler == null) { soleHandler = handler;//取最后一个实例 } else if (!handler.getClass().equals(soleHandler.getClass())) { // More than one type handlers registered. //不只一个TypeHandler类型得情况下 return null; } } return soleHandler; } /** * 获取未知类型TypeHandler实例 * @return {@link #unknownTypeHandler} */ public TypeHandler getUnknownTypeHandler() { return unknownTypeHandler; } /** * 注册 jdbcType 对应的 TypeHandler *

* 直接调用以{@link @jdbcType}作为key 和 {@link @handler}作为value加入到{@link #jdbcTypeHandlerMap}中 *

* @param jdbcType * @param handler */ public void register(JdbcType jdbcType, TypeHandler handler) { jdbcTypeHandlerMap.put(jdbcType, handler); } // // REGISTER INSTANCE // // Only handler /** * 注册TypeHandler *
    *
  1. 先尝试获取注解{@link MappedTypes}声明的类来调用{@link #register(Class, TypeHandler)}进行注册
  2. *
  3. 再尝试将{@link @typeHandler}转换成{@link TypeReference},从而获取到声明的泛型类型 * 来调用{@link #register(Class, TypeHandler)}进行注册
  4. *
  5. 都没有找到对应的java类型,就把javaType设置为null,调用{@link #register(Class, TypeHandler)}进行注册
  6. *
*/ @SuppressWarnings("unchecked") public void register(TypeHandler typeHandler) { //一个标记,当注册了handledType就会变成true boolean mappedTypeFound = false; //根据注解MappedType注册TypeHandler MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class); if (mappedTypes != null) { for (Class handledType : mappedTypes.value()) { register(handledType, typeHandler); mappedTypeFound = true; } } //根据TypeReference声明的泛型类型注册TypeHandler // @since 3.1.0 - try to auto-discover the mapped type if (!mappedTypeFound && typeHandler instanceof TypeReference) { try { TypeReference typeReference = (TypeReference) typeHandler; register(typeReference.getRawType(), typeHandler); mappedTypeFound = true; } catch (Throwable t) { // maybe users define the TypeReference with a different type and are not assignable, so just ignore it //可能用户定义的类型引用具有不同的类型,并且不可赋值,所以忽略它 } } //都没有找到对应的java类型,就当作null进行注册。 if (!mappedTypeFound) { register((Class) null, typeHandler); } } // java type + handler /** * 注册 javaType -- TypeHandle * 将{@link @javaType} 强转为 {@link Type}后,调用 {@link TypeHandlerRegistry#register(Type, TypeHandler)} */ public void register(Class javaType, TypeHandler typeHandler) { register((Type) javaType, typeHandler); } /** * 注册 javaType -- TypeHandle *

* 获取{@link @typeHandler}的{@link MappedJdbcTypes}注解信息赋值给{@link @mappedJdbcTypes}, * 在{@link @mappedJdbcTypes}不为null的情况下,遍历@mappedJdbcType所支持的jdbcType, * 对其调用 {@link TypeHandlerRegistry#register(Class, JdbcType, Class)} 注册,再判断是否支持null的jdbcType, * 支持的将null作为{@link TypeHandlerRegistry#register(Class, JdbcType, Class)}的第二参数进行调用; * 否则,直接将null作为{@link TypeHandlerRegistry#register(Class, JdbcType, Class)}的第二参数进行调用 *

*/ 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()) {//支持NULL的JdbcType register(javaType, null, typeHandler); } } else { register(javaType, null, typeHandler); } } /** * 注册 TypeHandler *

* 获取{@link @javaTypeReference}所声明的泛型类型,调用{@link #register(Class, TypeHandler)}进行注册 *

*/ public void register(TypeReference javaTypeReference, TypeHandler handler) { register(javaTypeReference.getRawType(), handler); } // java type + jdbc type + handler /** * 注册TypeHandler *

* 将{@link @type}强转成{@link Type},调用{@link #register(Type, JdbcType, TypeHandler)}进行注册 *

*/ public void register(Class type, JdbcType jdbcType, TypeHandler handler) { register((Type) type, jdbcType, handler); } /** * 注册 javaType -- jdbcType -- TypeHandler *

* 先从 {@link TypeHandlerRegistry#typeHandlerMap} 中获取{@link @javaType}对应的 JdbcType、TypeHandler映射关系的map * 并赋值给{@link @map},然后将{@link @jdbcType}作为key和{@link @handler}作为value设置到{@link @map}。 * 简单来说就是合并原有的,新建没有的。 * 最后还会获取{@link @handler}的Class类作为key,{@link @handler}作为value设置到{@link #allTypeHandlersMap}中 *

*

* 只要{@link @map} 是 null,或者是一个{@link TypeHandlerRegistry#NULL_TYPE_HANDLER_MAP}都会对{@link @map}重新实例化 * 一个新的{@link HashMap}并调用加入到 {@link #typeHandlerMap} 中。 *

*/ private void register(Type javaType, JdbcType jdbcType, TypeHandler handler) { if (javaType != null) { Map> map = typeHandlerMap.get(javaType); if (map == null || map == NULL_TYPE_HANDLER_MAP) {//就算 null类型TypeHandler Map都会重新赋值 map = new HashMap<>(); typeHandlerMap.put(javaType, map); } map.put(jdbcType, handler); } allTypeHandlersMap.put(handler.getClass(), handler); } // // REGISTER CLASS // // Only handler type /** * 注册TypeHandler *

* 通过注解{@link MappedTypes}获取{@link @typeHandlerClass}能处理的java类型,逐一调用{@link #register(Class, Class)}进行注册, * 没有注册到指定类型+TypeHandler映射关系时,用null当作javaTypeClass参数,调用{@link #getInstance(Class, Class)}得到TypeHandler的实例, * 然后调用{@link #register(TypeHandler)}进行注册。 *

*/ public void register(Class typeHandlerClass) { //已注册标记,当注册了指定类型+TypeHandler映射关系后会设置为tue boolean mappedTypeFound = false; MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class); if (mappedTypes != null) { for (Class javaTypeClass : mappedTypes.value()) { register(javaTypeClass, typeHandlerClass); mappedTypeFound = true; } } //没有注册到指定类型+TypeHandler映射关系,用null当作javaTypeClass进行注册 if (!mappedTypeFound) { register(getInstance(null, typeHandlerClass));//为啥不用register(Class, Class)方法呢,因为null没有Class } } // java type + handler type /** * 注册TypeHandler *

* 调用{@link Resources#classForName(String)}获取{@link @javaTypeClassName}和{@link @typeHandlerClassName}的Class, * 再调用{@link #register(Class, Class)} *

*/ public void register(String javaTypeClassName, String typeHandlerClassName) throws ClassNotFoundException { register(Resources.classForName(javaTypeClassName), Resources.classForName(typeHandlerClassName)); } /** * 注册TypeHandler *

* 传入{@link @javaTypeClass}和{@link @typeHandlerClass}到{@link #getInstance(Class, Class)}中得到TypeHandler的实例对象, * 再调用{@link #register(TypeHandler)}进行注册 *

*/ public void register(Class javaTypeClass, Class typeHandlerClass) { register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass)); } // java type + jdbc type + handler type /** * 注册TypeHandler *

* 传入{@link @javaTypeClass}和{@link @typeHandlerClass}到{@link #getInstance(Class, Class)}中得到TypeHandler的实例对象, * 再调用{@link #register(Type, JdbcType, TypeHandler)}进行注册 *

*/ public void register(Class javaTypeClass, JdbcType jdbcType, Class typeHandlerClass) { register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass)); } // Construct a handler (used also from Builders) /** * 创建TypeHandler实例对象 *

* 当{@link @javaTypeClass}不为null,会尝试通过带 Class 参数的构造方法进行实例化TypeHandler对象。 * 如果没有该构造方法,就通过无参构造方法实例化TypeHandler对象。 *

*/ @SuppressWarnings("unchecked") public TypeHandler getInstance(Class javaTypeClass, Class typeHandlerClass) { if (javaTypeClass != null) { /** * 尝试通过带 Class 参数的构造方法进行实例化TypeHandler对象。因为没有检查是否存在某个构造函数的方法,所以 * 使用捕捉异常的方式解决. */ try { Constructor c = typeHandlerClass.getConstructor(Class.class); return (TypeHandler) c.newInstance(javaTypeClass); } catch (NoSuchMethodException ignored) { // ignored 忽略没有该方法异常,使得执行下面代码。 } catch (Exception e) { throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e); } } //通过无参构造方法实例化TypeHandler try { Constructor c = typeHandlerClass.getConstructor(); return (TypeHandler) c.newInstance(); } catch (Exception e) { throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e); } } // scan /** * 扫描包中的 {@link TypeHandler} 的子类,并 调用 {@link TypeHandlerRegistry#register(TypeHandler)} * @param packageName */ public void register(String packageName) { ResolverUtil> resolverUtil = new ResolverUtil<>(); //扫描 packageName 里的 {@link TypeHandler} 子类 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); } } } // get information /** * 获取所有已注册的TypeHandler * @since 3.2.2 */ public Collection> getTypeHandlers() { return Collections.unmodifiableCollection(allTypeHandlersMap.values()); } }

你可能感兴趣的:(Mybatis-TypeHandler源码解析)