Mybatis中使用XML文件的地方主要有两个
1、mybatis的配置文件;
2、mybatis的各个mapper文件;
mybatis配置文件解析
首先来看一下mybatis中的配置文件解析,解析逻辑主要存在于XMLConfigBuilder类中。XMLConfigBuilder类继承了BaseBuilder类,拥有四个私有属性分别是:
// 该属性主要是保证同一个XMLConfigBuilder只解析一次。
private boolean parsed
// 解析XML文件主要的方法,对外提供了evalNode(String expression) 方法,解析之后返回XNode对象。
private final XPathParser parser
// Reflector类的工厂类,Reflector主要是获取指定Class的元数据信息(get,set方法,属性信息等)。
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory()
// 当前环境信息(环境信息有什么用呢?用处是如何体现出来的)
private String environment
XMLConfigBuilder类解析XML文件的入口方法是parse方法,parse方法中通过parsed字段判断了是否是该类的第一次解析,如果不是第一次解析则直接抛出BuilderException,如果是第一次解析则调用XPathParser类的evalNode(String expression)方法,获取xml文件中“configuration”元素对应的Node。然后调用parseConfiguration(XNode root)方法,解析的属性主要包括(properties,settings,typeAliases,plugins,objectFactory,objectWrapperFactory,reflectorFactory,environments,databaseIdProvider,typeHandlers,mappers)详情可见mybatis官方文档 http://www.mybatis.org/mybatis-3/zh/configuration.html
,解析出来的元素在Configuration对象中都有对应的属性来保存。如下是parse(),parseConfiguration(XNode root)方法。
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
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"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
Mapper对应的XML文件解析
Mapper文件的解析逻辑的入口是从XMLMapperBuilder类的parse方法开始的。XML文件解析主要分为了以下几步:
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingChacheRefs();
parsePendingStatements();
}
- 首先判断该资源是否已经加载
未加载的情况下,会执行以下逻辑- 解析Mapper文件中的所有元素
- 将该路径添加到configuration类中的ResourceLoader列表中,防止重复加载
- 绑定namespace(命名空间)
- 解析ResultMap元素
- 解析CacheRefs元素
- 解析Statement元素
下面来看一下如何解析**mapper.xml文件中的各个标签,configurationElement(parse.evalNode("/mapper"))方法的实现代码具体如下所示:
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
resultMapElements(context.evalNodes("/mapper/resultMap"));
sqlElement(context.evalNodes("/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);
}
}
从上面代码中可以看到,主要需要获取的元素包括(cache-ref,cache,/mapper/parameterMap,/mapper/resultMap,/mapper/sql,select|insert|update|delete)获取各个元素的节点信息是通过XNode类提供的evalNode(String)方法来获取的,
- 解析cache-ref标签,在mybatis中使用二级缓存时,通过cache-ref标签可以指定引用另一个命名空间的缓存。解析cache-ref标签,主要用到的CacheRefResolver和MapperBuilderAssistant类,解析时会根据指定的命名空间,获取该命名空间中的缓存,并指定为当前空间的Cache。
- 解析cache标签,cache标签可以定义该命名空间下使用的二级缓存,通过type,eviction,flushInterval,size,readOnly,blocking等标签来定制二级缓存的一些特性。在解析cache标签时,会首先解析type,eviction,flushInterval,size,readOnly,blocking这些元素,然后调用MapperBuilderAssistant类的userNewCache方法,创建指定的Cache类,绑定到当前命名空间下。
- 解析/mapper/parameterMap元素,定义了参数映射关系,mybatis文档中提示,该元素将要废弃了。
- 解析/mapper/resultMap元素,resultMap定义了返回值与实体类属性之间的映射的关系。逐步解析ResultMap标签下的子标签。最后调用MapperBuilderAssistant类的addResultMap方法,将解析完的ResultMap对象,保存到Configuration类中resultMaps属性中。
- 解析/mapper/sql元素,mapper文件中的sql标签是用来定义可被其他语句引用的可重复的语句块。解析到的sql标签对应的XNode会保存在XMLMapperBuilder类的sqlFragments属性中。
- 解析select|insert|update|delete元素,这四个元素对应的就是我们日常操作数据库的增删改查,之前定义的resultMap,cache,parameterMap,sql都有可能在这四个元素解析时用到。解析这四个标签是通过XMLStatementBuilder的parseStatementNode方法来解析,解析出的结果会封装为MapperStatement存入到Configuration类mapperStatments(StrictMap<String,MappedStatement>)属性中。
网友评论