- mybatis 是如何解析我们定义的mapper.xml文件?解析后如何存储?存在哪里?
- 想要解析必然先找到mapper.xml文件,mapperLocations 就是通过读取我们的配置获取到的xml Resource数组。
private Resource[] mapperLocations;
mybatis.mapper-locations=classpath:/mapper/*.xml
- 循环读取mapper文件,进行解析。
- 接下来我们看下解析是如何进行的?
- 首先构建了一个xmlMapperBuilder 对象,该对象包含了mapper.xml文件流,全路径文件名,Configuration 对象,以及当前对象的sqlFragments .即 sql 片段。
- 接下来调用XMLMapperBuilder的parse方法进行具体的解析工作。具体方法如下。
public void parse() {
//这里首先判断该资源是否已经加载过,已加载则不处理。
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
// XPathParser 类 parser.evalNode("/mapper") 构造一个XNode 节点对象。
public XNode evalNode(String expression) {
return evalNode(document, expression);
}
public XNode evalNode(Object root, String expression) {
Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
if (node == null) {
return null;
}
return new XNode(this, node, variables);
}
// configurationElement 方法
private void configurationElement(XNode context) {
try {
// 获取命名空间,可见mapper文件的命名空间不可为空也不能是空字符串
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
// 设置当前命名空间
builderAssistant.setCurrentNamespace(namespace);
// 解析cache-ref 相关配置
cacheRefElement(context.evalNode("cache-ref"));
// 解析cache配置
cacheElement(context.evalNode("cache"));
// 解析mapper 标签下parameterMap 配置 参数配置
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// 解析 mapper/resultMap 标签,放入到configuration 的属性resultMaps 。key 是由我们当前mapper文件的命名空间和标签定义里的id 拼接而来的。这样不同的命名空间就可以只用相同的id定义,由此命名空间起到了隔离的作用。
// protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 解析sql标签 放入到 configuration 的属性sqlFragments 参数里,sql片段信息
// protected final Map<String, XNode> sqlFragments = new StrictMap<&g