这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
时序图
sequenceDiagram
participant A as XMLMapperBuilder
participant B as MapperBuilderAssistant
participant C as ParameterMapping
participant D as TypeHandlerRegistry
A ->> B : buildParameterMapping
B ->> C : Builder
B ->> C : build
C ->> C : resolveTypeHandler
C ->> D : getTypeHandler
D ->> D : getJdbcHandlerMap
D -->> C : TypeHandler
C -->> A : ParameterMapping
详细步骤
XMLMapperBuilder#configurationElement
/**
* 解析映射文件的下层节点
* @param context 映射文件根节点
*/
private void configurationElement(XNode context) {
try {
// 读取当前映射文件namespace
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
// 映射文件中其他配置节点的解析
// 解析缓存标签
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));
// 解析参数映射
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// 解析结果集映射
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 解析sql标签
sqlElement(context.evalNodes("/mapper/sql"));
// 处理各个数据库操作语句
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
XMLMapperBuilder#parameterMapElement
/**
* 参数映射解析
*/
private void parameterMapElement(List<XNode> list) {
// 解析所有的parameterMap标签
for (XNode parameterMapNode : list) {
// 解析单个parameterMap标签中的属性
String id = parameterMapNode.getStringAttribute("id");
String type = parameterMapNode.getStringAttribute("type");
Class<?> parameterClass = resolveClass(type);
// 解析parameterMap标签内部具体的映射关系
List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
List<ParameterMapping> parameterMappings = new ArrayList<>();
for (XNode parameterNode : parameterNodes) {
// 解析parameter标签中的映射属性
String property = parameterNode.getStringAttribute("property");
String javaType = parameterNode.getStringAttribute("javaType");
String jdbcType = parameterNode.getStringAttribute("jdbcType");
String resultMap = parameterNode.getStringAttribute("resultMap");
String mode = parameterNode.getStringAttribute("mode");
String typeHandler = parameterNode.getStringAttribute("typeHandler");
Integer numericScale = parameterNode.getIntAttribute("numericScale");
// 根据配置参数模式枚举,若无配置,则为null
ParameterMode modeEnum = resolveParameterMode(mode);
// 根据配置解析javaType,若无配置,则为null
Class<?> javaTypeClass = resolveClass(javaType);
// 根据配置解析jdbcType,若无配置,则为null
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
// 根据配置解析类型处理器,若无配置,则为null
Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
// 解析参数映射
ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
parameterMappings.add(parameterMapping);
}
// 将解析完成的parameterMap添加到Configuration对象中的parameterMaps属性中
builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
}
}
MapperBuilderAssistant#buildParameterMapping
- 如果javaType为null,则通过反射解析
- 创建
ParameterMapping
对象并返回 - 创建对象时,根据javaType、jdbcType解析类型处理器
public ParameterMapping buildParameterMapping(
Class<?> parameterType,
String property,
Class<?> javaType,
JdbcType jdbcType,
String resultMap,
ParameterMode parameterMode,
Class<? extends TypeHandler<?>> typeHandler,
Integer numericScale) {
resultMap = applyCurrentNamespace(resultMap, true);
// Class parameterType = parameterMapBuilder.type();
// 反射获取参数的javaType
Class<?> javaTypeClass = resolveParameterJavaType(parameterType, property, javaType, jdbcType);
// 根据配置获取类型处理器
TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
// 若没有配置类型处理器,则在build方法中根据javaType,jdbcType解析类型处理器
return new ParameterMapping.Builder(configuration, property, javaTypeClass)
.jdbcType(jdbcType)
.resultMapId(resultMap)
.mode(parameterMode)
.numericScale(numericScale)
.typeHandler(typeHandlerInstance)
.build();
}
ParameterMapping#Builder
public Builder(Configuration configuration, String property, Class<?> javaType) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
parameterMapping.javaType = javaType;
// 设置参数模式为IN
parameterMapping.mode = ParameterMode.IN;
}
ParameterMapping#build
public ParameterMapping build() {
// 解析类型处理器
resolveTypeHandler();
// 校验
validate();
return parameterMapping;
}
ParameterMapping#resolveTypeHandler
private void resolveTypeHandler() {
if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) {
Configuration configuration = parameterMapping.configuration;
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
// 根据javaType和jdbcType解析类型处理器
parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);
}
}
TypeHandlerRegistry#getTypeHandler
/**
* 找出一个类型处理器
*
* @param type Java类型
* @param jdbcType JDBC类型
* @param <T> 类型处理器的目标类型
* @return 类型处理器
*/
@SuppressWarnings("unchecked")
private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
if (ParamMap.class.equals(type)) { // 是ParamMap,不是单一的Java类型
return null;
}
// 现根据Java类型找到对应的jdbcHandlerMap
Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);
TypeHandler<?> handler = null;
if (jdbcHandlerMap != null) {
// 根据JDBC类型寻找对应的处理器
handler = jdbcHandlerMap.get(jdbcType);
if (handler == null) {
// 使用null 作为键进行一次找寻,通过本类源码可知当前jdbcHandlerMap可能是EnumMap,也可能是HashMap
// EnumMap不允许键为null,因此总是返回null,HashMap允许键为null,这并不是一次无用功
handler = jdbcHandlerMap.get(null);
}
if (handler == null) {
// #591
// 如果jdbcHandlerMap只有一个类型处理器,就取出他
handler = pickSoleHandler(jdbcHandlerMap);
}
}
// 返回找到的类型处理器
// type drives generics here
return (TypeHandler<T>) handler;
}
TypeHandlerRegistry#getJdbcHandlerMap
private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMap(Type type) {
// 根据Java类型找到对应的jdbcTypeHandlerMap
Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(type);
if (NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap)) {
// 对应的jdbcTypeHandlerMap为空,则肯定没有符合的类型处理器
return null;
}
if (jdbcHandlerMap == null && type instanceof Class) {
// 未找到对应的jdbcTypeHandlerMap
Class<?> clazz = (Class<?>) type;
if (Enum.class.isAssignableFrom(clazz)) {
// clazz是个枚举类
Class<?> enumClass = clazz.isAnonymousClass() ? clazz.getSuperclass() : clazz;
// 寻找枚举类的处理器
jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(enumClass, enumClass);
if (jdbcHandlerMap == null) {
// 未找到枚举类的处理器则注册一个默认的并返回
register(enumClass, getInstance(enumClass, defaultEnumTypeHandler));
return typeHandlerMap.get(enumClass);
}
} else {
// 找寻其父类的处理器
jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz);
}
}
// 注册进typeHandlerMap
typeHandlerMap.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap);
return jdbcHandlerMap;
}
以上便是Mybatis解析parameterMap标签的过程。