上文分析到解析完mybatis-config.xml,将其中的信息装载进入configuration,并且生成了包含成员变量configuration的实例DefaultSqlSessionFactory。但其中有个还没有解析就是如果mapper使用url或者resource配置的时候,需要先解析对应的mapper.xml以便向mapperRegistry注册mapper。
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
首先看一下XMLMapperBuilder类,继承于BaseBuilder,看起来和XMLConfigBuilder作用差不多,区别就是这个类是用来解析mapper.xml的
public class XMLMapperBuilder extends BaseBuilder {
//XPath解析器
private final XPathParser parser;
//mapper构造器助手
private final MapperBuilderAssistant builderAssistant;
//可以被其他语句引用的可以重用语句块的集合
private final Map<String, XNode> sqlFragments;
//资源引用的地址
private final String resource;
@Deprecated
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
this(reader, configuration, resource, sqlFragments);
this.builderAssistant.setCurrentNamespace(namespace);
}
@Deprecated
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration, resource, sqlFragments);
}
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
this(inputStream, configuration, resource, sqlFragments);
this.builderAssistant.setCurrentNamespace(namespace);
}
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration, resource, sqlFragments);
}
private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
super(configuration);
//创建MapperBuilderAssistant对象
this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
this.parser = parser;
this.sqlFragments = sqlFragments;
this.resource = resource;
}
//解析Mapper XML配置文件
public void parse() {
//判断是否已经加载该配置文件
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("/mapper"));//处理mapper节点
configuration.addLoadedResource(resource);//将mapper文件添加到configuration.loadedResources中
bindMapperForNamespace();//注册mapper接口
}
//处理解析失败的ResultMap节点
parsePendingResultMaps();
//处理解析失败的CacheRef节点
parsePendingCacheRefs();
//处理解析失败的Sql语句节点
parsePendingStatements();
}
public XNode getSqlFragment(String refid) {
return sqlFragments.get(refid);
}
//解析mapper
private void configurationElement(XNode context) {
try {
//获取mapper节点的namespace属性
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
//设置builderAssistant的namespace属性
builderAssistant.setCurrentNamespace(namespace);
//解析cache-ref节点
cacheRefElement(context.evalNode("cache-ref"));
//重点分析 :解析cache节点----------------1-------------------
cacheElement(context.evalNode("cache"));
//解析parameterMap节点(已废弃)
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//重点分析 :解析resultMap节点(基于数据结果去理解)----------------2-------------------
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析sql节点
sqlElement(context.evalNodes("/mapper/sql"));
//重点分析 :解析select、insert、update、delete节点 ----------------3-------------------
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);
}
}
//解析select、insert、update、delete节点
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
//处理所有的sql语句节点并注册至configuration对象
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
//创建XMLStatementBuilder 专门用于解析sql语句节点
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
//解析sql语句节点
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
private void parsePendingResultMaps() {
//获得ResultMapResolver集合,并且遍历进行处理
Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
synchronized (incompleteResultMaps) {
Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
while (iter.hasNext()) {
try {
//执行解析
iter.next().resolve();
//移除
iter.remove();
} catch (IncompleteElementException e) {
// ResultMap is still missing a resource...
}
}
}
}
private void parsePendingCacheRefs() {
Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
synchronized (incompleteCacheRefs) {
Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
while (iter.hasNext()) {
try {
iter.next().resolveCacheRef();
iter.remove();
} catch (IncompleteElementException e) {
// Cache ref is still missing a resource...
}
}
}
}
private void parsePendingStatements() {
Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
synchronized (incompleteStatements) {
Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
while (iter.hasNext()) {
try {
iter.next().parseStatementNode();
iter.remove();
} catch (IncompleteElementException e) {
// Statement is still missing a resource...
}
}
}
}
//cache-ref节点的解析
private void cacheRefElement(XNode context) {
if (context != null) {
//获得当前的namespace名字以及配置中的namespace名称添加到CacheRef中
configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
//创建cacheRefResolver对象并且执行解析
CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
try {
cacheRefResolver.resolveCacheRef();
} catch (IncompleteElementException e) {
//解析失败添加到incompleteCacheRefs中
configuration.addIncompleteCacheRef(cacheRefResolver);
}
}
}
//解析Cache标签
private void cacheElement(XNode context) throws Exception {
if (context != null) {
//获取cache节点的type属性,默认为PERPETUAL
String type = context.getStringAttribute("type", "PERPETUAL");
//找到type对应的cache接口的实现
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
//读取eviction属性,既缓存的淘汰策略,默认LRU
String eviction = context.getStringAttribute("eviction", "LRU");
//根据eviction属性,找到装饰器
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
//读取flushInterval属性,既缓存的刷新周期
Long flushInterval = context.getLongAttribute("flushInterval");
//读取size属性,既缓存的容量大小
Integer size = context.getIntAttribute("size");
//读取readOnly属性,既缓存的是否只读
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
//读取blocking属性,既缓存的是否阻塞
boolean blocking = context.getBooleanAttribute("blocking", false);
Properties props = context.getChildrenAsProperties();
//通过builderAssistant创建缓存对象,并添加至configuration
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
private void parameterMapElement(List<XNode> list) throws Exception {
for (XNode parameterMapNode : list) {
String id = parameterMapNode.getStringAttribute("id");
String type = parameterMapNode.getStringAttribute("type");
Class<?> parameterClass = resolveClass(type);
List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
List<ParameterMapping> parameterMappings = new ArrayList<>();
for (XNode parameterNode : parameterNodes) {
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");
ParameterMode modeEnum = resolveParameterMode(mode);
Class<?> javaTypeClass = resolveClass(javaType);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
parameterMappings.add(parameterMapping);
}
builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
}
}
//解析resultMap节点,实际就是解析sql查询的字段与pojo属性之间的转化规则
private void resultMapElements(List<XNode> list) throws Exception {
//遍历所有的resultmap节点
for (XNode resultMapNode : list) {
try {
//解析具体某一个resultMap节点
resultMapElement(resultMapNode);
} catch (IncompleteElementException e) {
// ignore, it will be retried
}
}
}
//解析resultMap节点
private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
}
//解析resultMap节点
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
//获取resultmap节点的id属性
String id = resultMapNode.getStringAttribute("id",
resultMapNode.getValueBasedIdentifier());
//获取resultmap节点的type属性
String type = resultMapNode.getStringAttribute("type",
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType",
resultMapNode.getStringAttribute("javaType"))));
//获取resultmap节点的extends属性,描述继承关系
String extend = resultMapNode.getStringAttribute("extends");
//获取resultmap节点的autoMapping属性,是否开启自动映射
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
//从别名注册中心获取entity的class对象
Class<?> typeClass = resolveClass(type);
Discriminator discriminator = null;
//记录子节点中的映射结果集合
List<ResultMapping> resultMappings = new ArrayList<>();
resultMappings.addAll(additionalResultMappings);
//从xml文件中获取当前resultmap中的所有子节点,并开始遍历
List<XNode> resultChildren = resultMapNode.getChildren();
for (XNode resultChild : resultChildren) {
if ("constructor".equals(resultChild.getName())) {//处理<constructor>节点
processConstructorElement(resultChild, typeClass, resultMappings);
} else if ("discriminator".equals(resultChild.getName())) {//处理<discriminator>节点
discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {//处理<id> <result> <association> <collection>节点
List<ResultFlag> flags = new ArrayList<>();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);//如果是id节点,向flags中添加元素
}
//创建ResultMapping对象并加入resultMappings集合中
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
//实例化resultMap解析器
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
//通过resultMap解析器实例化resultMap并将其注册到configuration对象
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
}
//处理constructor节点
private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
List<XNode> argChildren = resultChild.getChildren();
//遍历子节点
for (XNode argChild : argChildren) {
//创建ResultFlag集合
List<ResultFlag> flags = new ArrayList<>();
flags.add(ResultFlag.CONSTRUCTOR);
if ("idArg".equals(argChild.getName())) {
flags.add(ResultFlag.ID);
}
//将当前子节点构建成ResultMapping对象并且添加到ResultMappings中
resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
}
}
//处理discrimination节点
private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
//解析各种属性
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String typeHandler = context.getStringAttribute("typeHandler");
//解析各种属性对应的类
Class<?> javaTypeClass = resolveClass(javaType);
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
Map<String, String> discriminatorMap = new HashMap<>();
for (XNode caseChild : context.getChildren()) {
String value = caseChild.getStringAttribute("value");
String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings));
//解析成discriminatorMap
discriminatorMap.put(value, resultMap);
}
//创建Discriminator对象
return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
}
private void sqlElement(List<XNode> list) throws Exception {
if (configuration.getDatabaseId() != null) {
sqlElement(list, configuration.getDatabaseId());
}
sqlElement(list, null);
}
//解析sql节点们
private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
//遍历所有的sql节点
for (XNode context : list) {
//获得databaseId属性
String databaseId = context.getStringAttribute("databaseId");
//获得id属性
String id = context.getStringAttribute("id");
//获得完整的id属性,在原来id前加上名称空间
id = builderAssistant.applyCurrentNamespace(id, false);
if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
//添加到sqlFragments
sqlFragments.put(id, context);
}
}
}
//判断databaseId是否匹配
private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
if (requiredDatabaseId != null) {
//如果不匹配返回false
if (!requiredDatabaseId.equals(databaseId)) {
return false;
}
} else {
//一个是null一个不是null 返回false
if (databaseId != null) {
return false;
}
//判断是否已经存在
if (this.sqlFragments.containsKey(id)) {
XNode context = this.sqlFragments.get(id);
// 若存在,则判断原有的 sqlFragment 是否 databaseId 为空。因为,当前 databaseId 为空,这样两者才能匹配。
if (context.getStringAttribute("databaseId") != null) {
return false;
}
}
}
return true;
}
//根据resultmap中的子节点信息,创建resultMapping对象
private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
//获得各类属性
String property;
if (flags.contains(ResultFlag.CONSTRUCTOR)) {
property = context.getStringAttribute("name");
} else {
property = context.getStringAttribute("property");
}
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String nestedSelect = context.getStringAttribute("select");
String nestedResultMap = context.getStringAttribute("resultMap",
processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
String notNullColumn = context.getStringAttribute("notNullColumn");
String columnPrefix = context.getStringAttribute("columnPrefix");
String typeHandler = context.getStringAttribute("typeHandler");
String resultSet = context.getStringAttribute("resultSet");
String foreignColumn = context.getStringAttribute("foreignColumn");
boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
//获得各种属性对应的类
Class<?> javaTypeClass = resolveClass(javaType);
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
//使用建造者模式创建resultMapping对象
return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
}
//处理内嵌的ResultMap的情况
private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings) throws Exception {
if ("association".equals(context.getName())
|| "collection".equals(context.getName())
|| "case".equals(context.getName())) {
if (context.getStringAttribute("select") == null) {
//解析并且返回resultMap
ResultMap resultMap = resultMapElement(context, resultMappings);
return resultMap.getId();
}
}
return null;
}
//注册mapper接口
private void bindMapperForNamespace() {
//获取命名空间
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
//通过命名空间获取mapper接口的class对象
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
//ignore, bound type is not required
}
if (boundType != null) {
if (!configuration.hasMapper(boundType)) {//是否已经注册过该mapper接口?
// Spring may not know the real resource name so we set a flag
// to prevent loading again this resource from the mapper interface
// look at MapperAnnotationBuilder#loadXmlResource
//将命名空间添加至configuration.loadedResource集合中
configuration.addLoadedResource("namespace:" + namespace);
//将mapper接口添加到mapper注册中心
configuration.addMapper(boundType);
}
}
}
}
}
CacheRefResolver Cache指向解析器
public class CacheRefResolver {
private final MapperBuilderAssistant assistant;
private final String cacheRefNamespace;
public CacheRefResolver(MapperBuilderAssistant assistant, String cacheRefNamespace) {
this.assistant = assistant;
this.cacheRefNamespace = cacheRefNamespace;
}
//会调用assistant中的useCacheRef方法来获得指定的Cache对象
public Cache resolveCacheRef() {
return assistant.useCacheRef(cacheRefNamespace);
}
}
ResultMapResolver ResultMap 解析器
public class ResultMapResolver {
private final MapperBuilderAssistant assistant;
private final String id;
private final Class<?> type;
private final String extend;
private final Discriminator discriminator;
private final List<ResultMapping> resultMappings;
private final Boolean autoMapping;
public ResultMapResolver(MapperBuilderAssistant assistant, String id, Class<?> type, String extend, Discriminator discriminator, List<ResultMapping> resultMappings, Boolean autoMapping) {
this.assistant = assistant;
this.id = id;
this.type = type;
this.extend = extend;
this.discriminator = discriminator;
this.resultMappings = resultMappings;
this.autoMapping = autoMapping;
}
//创建resultMap对象
public ResultMap resolve() {
return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
}
}
本文深入解析MyBatis框架中Mapper XML配置文件的加载与解析过程,详细介绍了XMLMapperBuilder类如何处理mapper.xml文件,包括解析缓存、参数映射、结果映射等关键节点,以及如何注册Mapper接口。
8057

被折叠的 条评论
为什么被折叠?



