Ibatis的部类处理器TypeHandler解析
Ibatis的类型处理器TypeHandler解析原文来自: http://blog.csdn.net/lovingprince/article/details/276884
Ibatis的类型处理器TypeHandler解析
原文来自: http://blog.csdn.net/lovingprince/article/details/2768849
?
Ibatis允许用户像在hibernate中一样定义自己的类型,但是,用户自定义类型需要与数据库中的字段类型进行对应。它的处理方法是允许我们扩展TypeHandler。Ibatis框架在处理该数据类型时就会自动调用TypeHandler进行类型转换,非常方便,ibatis中所有的类型都有它自己的TypeHandler,只是一些常用的数据类类型它已经给我们实现了而已。
在配置文件中,我们有两个地方可以配置这种处理器。
? 第一个地方是sqlMap文件中标签ResultMap或者ParameterMap中的TypeHandler属性,这里配置的handler是局部属性,只会在该ResultMap中才会进行转换。
????<resultMap?id="UserOrder"?class="UserOrderDO"?groupBy="id"> - ?????????...... ????????<result?property="tripType"?column="trip_Type"
- ?????????typeHandler="com.taobao.et.biz.dal.common.EnumTypeHandlerCallBack"/> ??????????......
- ????</resultMap>
?第二个地方是sqlMapConfig文件中的标签typeHandlers中配置typeHandle子标签,这里配置的标签是全局属性,任何只要匹配该子标签的地方都会自动使用该Handler.
<typeHandlers> - <typeHandler?jdbcType="CLOB"?javaType="java.lang.String"?callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/> </typeHandlers>
例如这里的全局配置,如果此时某个数据库字段的jdbcType是CLOB类型,并且映射的JavaType类型是字符串类型,那么就会自动调用这里的callback来实行类型转换。
?
??? 那么Ibatis是如何确定使用哪一个TypeHandler的呢?!
??? 它会在自己的局部区域寻找是否在配置文件中配置了Handler,找到了就使用这个handler,如果没有找到,就会查找是否有全局handler,也就是第二种方式配置的handler,这里要注意,可能我们也没有在全局配置文件中配置handler,此时,Ibatis就会根据实际类型配置默认的handler。
? 我们来看一些关键代码,按照查找步骤,这里我去掉了异常,只看关键的部分。
? 第一步:从局部Reultmap中取出配置属性。
- ??????String?propertyName?=?childAttributes.getProperty("property"); ????????String?nullValue?=?childAttributes.getProperty("nullValue");
- ????????String?jdbcType?=?childAttributes.getProperty("jdbcType"); ????????String?javaType?=?childAttributes.getProperty("javaType");
- ????????String?columnName?=?childAttributes.getProperty("column"); ????????String?columnIndex?=?childAttributes.getProperty("columnIndex");
- ????????String?statementName?=?childAttributes.getProperty("select"); ????????String?resultMapName?=?childAttributes.getProperty("resultMap");
- ????????String?callback?=?childAttributes.getProperty("typeHandler"); ????????callback?=?vars.typeHandlerFactory.resolveAlias(callback);
- ????????javaType?=?vars.typeHandlerFactory.resolveAlias(javaType);
- ????????TypeHandler?handler?=?null; ????????if?(callback?!=?null)?{ // 注意这里,如果配置了就使用这个配置的handler
- ????????????Object?impl?=?Resources.classForName(callback).newInstance(); ????????????if?(impl?instanceof?TypeHandlerCallback)?{
- ??????????????handler?=?new?CustomTypeHandler((TypeHandlerCallback)?impl); ????????????}?else?if?(impl?instanceof?TypeHandler)?{
- ??????????????handler?=?(TypeHandler)?impl; ????????????}?else?{
- ??????????????throw?new?NestedRuntimeException?("The?class?''?is?not?a?valid?implementation?of?TypeHandler?or?TypeHandlerCallback"); ????????????}
- ????????}?else?{//如果没有配置,就到这里来找 ??????????????????handler?=?resolveTypeHandler(vars.client.getDelegate().getTypeHandlerFactory(),?vars.currentResultMap.getResultClass(),?propertyName,?javaType,?jdbcType,?true);
- ????????}
?
第二步,如果局部配置中没有找到,就到下面去找。
?
public?TypeHandler?resolveTypeHandler(TypeHandlerFactory?typeHandlerFactory,?Class?clazz,?String?propertyName,?String?javaType,?String?jdbcType,?boolean?useSetterToResolve)?{ - ????TypeHandler?handler?=?null; ????if?(clazz?==?null)?{
- ??????//?Unknown ??????handler?=?typeHandlerFactory.getUnkownTypeHandler();
- ????}?else?if?(DomTypeMarker.class.isAssignableFrom(clazz))?{ ??????//?DOM
- ??????handler?=?typeHandlerFactory.getTypeHandler(String.class,?jdbcType); ????}?else?if?(java.util.Map.class.isAssignableFrom(clazz))?{
- ??????//?Map ??????if?(javaType?==?null)?{
- ????????handler?=?typeHandlerFactory.getUnkownTypeHandler();?//BUG?1012591?-?typeHandlerFactory.getTypeHandler(java.lang.Object.class,?jdbcType); ??????}?else?{
- ????????try?{ ??????????Class?javaClass?=?Resources.classForName(javaType);
- ??????????handler?=?typeHandlerFactory.getTypeHandler(javaClass,?jdbcType); ????????}?catch?(Exception?e)?{
- ??????????throw?new?NestedRuntimeException("Error.??Could?not?set?TypeHandler.??Cause:?"?+?e,?e); ????????}
- ??????} ????}?else?if?(typeHandlerFactory.getTypeHandler(clazz,?jdbcType)?!=?null)?{
- ??????//?Primitive ??????handler?=?typeHandlerFactory.getTypeHandler(clazz,?jdbcType);
- ????}?else?{ ??????//?JavaBean
- ??????if?(javaType?==?null)?{ ????????if?(useSetterToResolve)?{
- ??????????Class?type?=?PROBE.getPropertyTypeForSetter(clazz,?propertyName); ??????????handler?=?typeHandlerFactory.getTypeHandler(type,?jdbcType);
- ????????}?else?{ ??????????Class?type?=?PROBE.getPropertyTypeForGetter(clazz,?propertyName);
- ??????????handler?=?typeHandlerFactory.getTypeHandler(type,?jdbcType); ????????}
- ??????}?else?{ ????????try?{
- ??????????Class?javaClass?=?Resources.classForName(javaType); ??????????handler?=?typeHandlerFactory.getTypeHandler(javaClass,?jdbcType);
- ????????}?catch?(Exception?e)?{ ??????????throw?new?NestedRuntimeException("Error.??Could?not?set?TypeHandler.??Cause:?"?+?e,?e);
- ????????} ??????}
- ????} ????return?handler;
- ??}
- 相信大家已经很明白了,其实要找一个Handler,主要就是需要javaType和jdbcType,而这两个参数要么通过反射得到,要么通过配置文件中得到。因此,为了明确我们一般都在配置文件中进行申明。
- 最后来看一点 typeHandlerFactory.getTypeHandler(clazz,?jdbcType)是怎么实现的。
??public?TypeHandler?getTypeHandler(Class?type,?String?jdbcType)?{ - ????Map?jdbcHandlerMap?=?(Map)?typeHandlerMap.get(type);//首先根据JAVA类型 ????TypeHandler?handler?=?null;
- ????if?(jdbcHandlerMap?!=?null)?{ ??????handler?=?(TypeHandler)?jdbcHandlerMap.get(jdbcType);//每个JDBC类型
- ??????if?(handler?==?null)?{ ????????handler?=?(TypeHandler)?jdbcHandlerMap.get(null);
- ??????} ????}
- ????return?handler; ??}
- 其实一个Handler=javaType+jdbcType 。