版本说明:mybatis3.4.0
文章目录
一、我们关注mapper的解析
解析的内容太多了,大家可以自己去查看源码、在这里我们关注mapper的解析、mapper解析成多个MappedStatement
上面章提到的XMLConfigBuilder里面:
this.mapperElement(root.evalNode("mappers"));
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
Iterator i$ = parent.getChildren().iterator();
while(true) {
while(i$.hasNext()) {
XNode child = (XNode)i$.next();
String resource;
if ("package".equals(child.getName())) {//取出的标签package
resource = child.getStringAttribute("name");
this.configuration.addMappers(resource);
} else {
resource = child.getStringAttribute("resource");//取出的标签是resource
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
XMLMapperBuilder mapperParser;
InputStream inputStream;
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
inputStream = Resources.getResourceAsStream(resource);//取出mapepr.xml进行解析
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
inputStream = Resources.getUrlAsStream(url);
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
mapperParser.parse();
} else {
if (resource != null || url != null || mapperClass == null) {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
Class<?> mapperInterface = Resources.classForName(mapperClass);
this.configuration.addMapper(mapperInterface);
}
}
}
return;
}
}
}
解析mapper标签,有两种形式,分别是扫描package和mapper标签、只能使用一种方式加载mapper
<mappers>
<mapper resource="mapper/AbcMapper.xml"/>
</mappers>
<mappers>
<package name="com.ys.mapper"/>
</mappers>
2、XMLMapperBuilder解析
public void parse() {
if (!this.configuration.isResourceLoaded(this.resource)) {
this.configurationElement(this.parser.evalNode("/mapper"));//关注mapper.xml的解析、里面解析了MappedStatement
this.configuration.addLoadedResource(this.resource);
//这里注册mapper动态代理对象。并且注册注解的方法(@select等)成MappedStatement、详情看下面
this.bindMapperForNamespace();
}
this.parsePendingResultMaps();
this.parsePendingChacheRefs();
this.parsePendingStatements();
}
//..
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace != null && !namespace.equals("")) {
this.builderAssistant.setCurrentNamespace(namespace);
this.cacheRefElement(context.evalNode("cache-ref"));
this.cacheElement(context.evalNode("cache"));
this.parameterMapElement(context.evalNodes("/mapper/parameterMap"));
this.resultMapElements(context.evalNodes("/mapper/resultMap"));
this.sqlElement(context.evalNodes("/mapper/sql"));
this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));//解析执行的sql标签
} else {
throw new BuilderException("Mapper's namespace cannot be empty");
}
} catch (Exception var3) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + var3, var3);
}
}
//..
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
Iterator i$ = list.iterator();
while(i$.hasNext()) {
XNode context = (XNode)i$.next();//可以看到这里有出现了Builder对象、XMLStatementBuilder
XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration, this.builderAssistant, context, requiredDatabaseId);
try {
statementParser.parseStatementNode();
} catch (IncompleteElementException var7) {
this.configuration.addIncompleteStatement(statementParser);
}
}
}
3、XMLStatementBuilder的解析把上面的(select|insert|update|delete)标签解析成MappedStatement对象、用于执行
public void parseStatementNode() {
String id = this.context.getStringAttribute("id");
String databaseId = this.context.getStringAttribute("databaseId");
if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
//....
SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);//我们关注这个
//.....
this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
}
SqlSource
/**
* Represents the content of a mapped statement read from an XML file or an annotation.
* It creates the SQL that will be passed to the database out of the input parameter received from the user.
*
* @author Clinton Begin
*/
// 以上注释就不作翻译了.
public interface SqlSource {
BoundSql getBoundSql(Object parameterObject);
}
SqlSource
StaticSqlSource // SqlSource实例的直接构造者就是 SqlSourceBuilder, 而SqlSourceBuilder中的parse方法所返回的是StaticSqlSource实例.
RawSqlSource //
ProviderSqlSource
DynamicSqlSource
一个例子:下面属性储存着执行的sql
public class StaticSqlSource implements SqlSource {
private String sql;
private List<ParameterMapping> parameterMappings;
private Configuration configuration;
//....
}
4、注册mapper,
private void bindMapperForNamespace() {
String namespace = this.builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class boundType = null;
try {
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException var4) {
}
if (boundType != null && !this.configuration.hasMapper(boundType)) {
this.configuration.addLoadedResource("namespace:" + namespace);
this.configuration.addMapper(boundType);
}
}
}
}
public class MapperRegistry {
//..
public <T> void addMapper(Class<T> type) {
//...
this.knownMappers.put(type, new MapperProxyFactory(type));
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
parser.parse();//解析注解
//...
}
//...
}
public class MapperAnnotationBuilder {
//...
public void parse() {
//..
for(int i$ = 0; i$ < len$; ++i$) {
Method method = arr$[i$];
try {
if (!method.isBridge()) {
this.parseStatement(method);//把方法解析成MappedStatement
}
} catch (IncompleteElementException var8) {
this.configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
//..
}
//..
}
我们已经知道如何解析mapper的一部分流程了、