loadCustomLogImpl(settings);
/**
- 解析 typeAliases配置文件
*/
typeAliasesElement(root.evalNode(“typeAliases”));
/**
- 解析 plugins 配置文件
- 这个是插件,可以动态的拦截sql执行
*/
pluginElement(root.evalNode(“plugins”));
objectFactoryElement(root.evalNode(“objectFactory”));
objectWrapperFactoryElement(root.evalNode(“objectWrapperFactory”));
reflectorFactoryElement(root.evalNode(“reflectorFactory”));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode(“environments”));
databaseIdProviderElement(root.evalNode(“databaseIdProvider”));
typeHandlerElement(root.evalNode(“typeHandlers”));
/**
- 加载 mapper.xml 文件
*/
mapperElement(root.evalNode(“mappers”));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
1.4.1: mapperElement(root.evalNode(“mappers”));
解析mapper.xml文件,以及接口方法的注解
public class XMLConfigBuilder extends BaseBuilder {
/**
- mapper隐射文件解析
- @param parent
- @throws Exception
/
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
/* - 解析 <package
/
if (“package”.equals(child.getName())) {
String mapperPackage = child.getStringAttribute(“name”);
/*
- 添加所有包下的接口
- 实际调用 configuration.addMapper(mapperInterface);
/
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute(“resource”);
String url = child.getStringAttribute(“url”);
String mapperClass = child.getStringAttribute(“class”);
/* - 解析 <mapper resource
-
<mappers>
-
<mapper resource="mapper/UserMapper.xml"/>
-
</mappers>
/
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
/*
- mapper.xml 解析器
/
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
/* - 开始解析 mapper.xml文件
- 重点分析这个 同样也会调用 configuration.addMapper(mapperInterface); 这个方法
/
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
/* - 解析 <mapper url
/
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
/* - 解析 <mapper class
/
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
/* - 以下代码可以看出 url resource class 三个属性只能选择一个,否则就会报错
*/
throw new BuilderException(“A mapper element may only specify a url, resource or class, but not more than one.”);
}
}
}
}
}
}
1.4.2:mapperParser.parse();解析
我的UserMapper.xml文件内容为:
<?xml version="1.0" encoding="UTF-8"?> select * from `user` where userId = #{userId}UserMapper接口内容为:
package com.mapper;
import com.entity.User;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select(“select * from user
where userId = 2”)
User findById(int userId);
}
疑问?UserMapper.xml有<select id=“findById”,而在接口中的findById方法我又加了一个@Select注解;那么执行会选择哪一条Sql执行还是报错呢?
以UserMapper.xml为例子解析,可以看到 resource = mapper/UserMapper.xml
public class XMLMapperBuilder extends BaseBuilder {
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
/**
- 解析 mapper.xml文件内容
/
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
/* - 解析 mapper.xml的
- namespace指定的{UserMapper}接口的注解信息
*/
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
}
1.4.3:configurationElement(parser.evalNode("/mapper"));
解析 mapper.xml文件内容
public class XMLMapperBuilder extends BaseBuilder {
private void configurationElement(XNode context) {
try {
/**
- namespace属性
/
String namespace = context.getStringAttribute(“namespace”);
if (namespace == null || namespace.equals("")) {
/* - 不指定 namespace会报错哦 由此得知 namespace属性是必须指定的
/
throw new BuilderException(“Mapper’s namespace cannot be empty”);
}
builderAssistant.setCurrentNamespace(namespace);
/* - 解析 cache-ref
/
cacheRefElement(context.evalNode(“cache-ref”));
/* - 解析 cache
/
cacheElement(context.evalNode(“cache”));
/* - 解析 parameterMap
/
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
/* - 解析 resultMap
/
resultMapElements(context.evalNodes("/mapper/resultMap"));
/* - 解析 sql
/
sqlElement(context.evalNodes("/mapper/sql"));
/* - 解析 sql语句 select|insert|update|delete
- 重点分析这里,这里的解析会关联到 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);
}
}
}
1.4.4:buildStatementFromContext(context.evalNodes(“select|insert|update|delete”));
解析 sql语句 select|insert|update|delete;list参数内容是select|insert|update|delete的Sql语句