我们在mybatis中写的很多mapper.xml文件就是通过XMLConfigurationBuilder中的mapperElement进行解析的,下面我们好好研究一下mapper.xml文件
下面就是整个mapperElement方法中的内容,为了简化我只保留关于resource的内容。
private void mapperElement(XNode parent) throws Exception {
for (XNode child : parent.getChildren()) {
ErrorContext.instance() .resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
//解析mapper.xml
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource,
configuration.getSqlFragments());
}
}
在mapperElement重要加载mapper.xml ,然后把解析工作交给了XMLMapperBuilder
XMLMapperBuilder
XMLMapperBuilder中的属性字段:
- XPathParser parser:用户解析xml
- MapperBuilderAssistant builderAssistant:用于帮助XMLMapperBuilder把解析出的内容进行对象化。例如:resultMapper标签映射成了类ResultMap。
- Map<String, XNode> sqlFragments:暂时不清楚
- String resource:mapper.xml所在的资源路径。
这个类继承了BaseBuilder,在BaseBuilde中有三个字段:
- Configuration configuration:各种配置信息,来源于XMLConfigurationBuilder中的configuration
- TypeAliasRegistry typeAliasRegistry:别名注册器,里面记录各种类的简称和对应的Class,例如:
public class TypeAliasRegistry { private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>(); public TypeAliasRegistry() { registerAlias("string", String.class); registerAlias("byte", Byte.class); .... } .... }
- TypeHandlerRegistry typeHandlerRegistry:里面维护了各种java类型和其对应的处理器。例如:
public final class TypeHandlerRegistry { .... public TypeHandlerRegistry() { register(Boolean.class, new BooleanTypeHandler()); register(boolean.class, new BooleanTypeHandler()); register(JdbcType.BOOLEAN, new BooleanTypeHandler()); register(JdbcType.BIT, new BooleanTypeHandler()); ... } ... }
下面我们看看XMLMapperBuilder的parse方法中都做了什么事情
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
//解析mapper中的各种标签
configurationElement(parser.evalNode("/mapper"));
//表示该资源已经被加载过了
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingChacheRefs();
parsePendingStatements();
}
主要的解析内容都在configurationElement方法中,下面我们看看configurationElement方法(只保留关键部分)
private void configurationElement(XNode context) {
String namespace = context.getStringAttribute("namespace");
builderAssistant.setCurrentNamespace(namespace);
//解析cache-ref
cacheRefElement(context.evalNode("cache-ref"));
//解析cache
cacheElement(context.evalNode("cache"));
//已经废弃 不看
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//解析resultMap标签
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析sql标签
sqlElement(context.evalNodes("/mapper/sql"));
//解析insert update delete select标签..
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
}
这一篇文章我们找到了解析mapper.xml文件的入口,下面我们看看mybatis是如何解析各种标签的。