分析
MyBatis整合Spring的实现(1)中代码实现的4.4拦截器后面文章根据具体例子分析,分析4.5、4.6可以知道,这2个都是去生成类型管理器TypeHandlerRegistry类,下面就来分析代码。
1 属性
这里的属性都是定义基本的类型,所以我们针对每个Map属性,挑选出一条来进行分析。
1.1 reversePrimitiveMap
private static final Map<Class<?>, Class<?>> reversePrimitiveMap = new HashMap<Class<?>, Class<?>>(){ private static final long serialVersionUID = 1L; { put(Byte.class, byte.class); put(Short.class, short.class); put(Integer.class, int.class); put(Long.class, long.class); put(Float.class, float.class); put(Double.class, double.class); put(Boolean.class, boolean.class); put(Character.class, char.class); } };
首先是原始类型的对象对应原始类型的Class。
1.2 JDBC类型对应的类型处理器------JDBC_TYPE_HANDLER_MAP
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class); register(JdbcType.CHAR, new StringTypeHandler());
上面就是数据库中CHAR类型,对应StringTypeHandler处理器。
1.3 JAVA类型、数据库类型、处理器对应MAP------TYPE_HANDLER_MAP
private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>(); register(String.class, JdbcType.CHAR, new StringTypeHandler()); private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) { if (javaType != null) { Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType); if (map == null) { map = new HashMap<JdbcType, TypeHandler<?>>(); TYPE_HANDLER_MAP.put(javaType, map); } map.put(jdbcType, handler); if (reversePrimitiveMap.containsKey(javaType)) { register(reversePrimitiveMap.get(javaType), jdbcType, handler); } } ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler); }
上面就是JAVA类型为String,数据库类型为CHAR,对应StringTypeHandler处理器。
1.4 未知处理类型------UNKNOWN_TYPE_HANDLER
private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this); register(Object.class, UNKNOWN_TYPE_HANDLER); register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER); register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
未知类型处理比较少,就全部列出来,也就是最大范围,Object是所有类的父类。
1.5 处理器本身------ALL_TYPE_HANDLERS_MAP
private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();
本文1.3就已经有这部分代码的处理,把处理器的Class作为Map的key,value为处理器本身。
2 类型处理器作用------StringTypeHandler
处理器有很多,这里只选择一个来进行分析。
2.1 父类BaseTypeHandler
上图是父类BaseTypeHandler,使用了泛型,并继承TypeReference,实现TypeHandler。
2.2 接口TypeHandler
写过底层JDBC代码的朋友都清楚,这几个方法是做什么的。
2.2.1 setParameter
当JAVA代码中使用PreparedStatement时,因为是预编译,所以值是后来设置的,这个方法就是对相应的?设置值。
2.2.2 T getResult(ResultSet rs, String columnName)
方法是通过最后的列名获取相应的列的值。
2.2.3 T getResult(ResultSet rs, int columnIndex)
方法是通过顺序获取相应的列的值。
2.2.4 T getResult(CallableStatement cs, int columnIndex)
方法是存储过程调用返回的结果,也是通过顺序获取相应的列的值。
2.3 TypeReference
不清楚,以后再补充。。。
3 类型管理器,Spring配置属性------包/类
if (hasLength(this.typeHandlersPackage)) { String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); for (String packageToScan : typeHandlersPackageArray) { configuration.getTypeHandlerRegistry().register(packageToScan); if (this.logger.isDebugEnabled()) { this.logger.debug("Scanned package: '" + packageToScan + "' for type handlers"); } } } if (!isEmpty(this.typeHandlers)) { for (TypeHandler<?> typeHandler : this.typeHandlers) { configuration.getTypeHandlerRegistry().register(typeHandler); if (this.logger.isDebugEnabled()) { this.logger.debug("Registered type handler: '" + typeHandler + "'"); } } }
根据前一章,这里很好分析,代码做了哪些事情。这里不再过多的分析。
总结:
类型处理器的作用,就是在SQL设置值(PreparedStatement)时,把JAVA类型的对象转换成数据库类型。
在SQL执行结果返回时,把数据库类型的数据转换成JAVA类型对象。
实际应用中,默认的类型处理器基本已经够用。
这里只是针对字符串类型进行分析,其它类型也都一样,可以自行看看源码。如果对JDBC不太清楚,可以找找资料,写个测试类,看看JDBC代码。能更好的了解,MyBatis这里的设计理念。
注:类型也支持注解方式,作者没有使用过注解,也就没有分析关于注解方式。