MyBatis 3 解析 mybatis-config.xml 配置

用户头像
杨家昌
关注
发布于: 2020 年 05 月 07 日
MyBatis 3 解析mybatis-config.xml配置

按照惯例,直接上干货。

MyBatis初始化工作包括加载和解析mybatis-config.xml配置文件、映射文件和相关注解信息。初始化入口是SqlSessionFactoryBuider.build()方法。

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
}
}
}

XMLConfigBuilder对象继承BaseBuider抽象类,用来解析mybatis-config.xml配置文件。而BaseBuider类中主要包括3个配置项:

public abstract class BaseBuilder {
protected final Configuration configuration; //全局唯一配置对象
protected final TypeAliasRegistry typeAliasRegistry; //解析mybatis-config.xml中<typeAliases>标签
protected final TypeHandlerRegistry typeHandlerRegistry; //解析mybatis-config.xml中<typeHandlers>标签
}

其中TypeAliasRegistry和TypeHandlerRegistry在Configuration初始化时配创建出来,也是全局唯一配置:

public class Configuration {
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
}

当然,Configuration类中并不是只有以上2项配置,实际上MyBatis的配置都存放在这里,这里就不一一展开说了。

MyBatis的初始化是在XMLConfigBuilder类中完成的,由其负责解析mybatis-config.xml配置文件,其核心属性包括:

public class XMLConfigBuilder extends BaseBuilder {
//是否已经解析过mybatis-config.xml文件
private boolean parsed;
//用来解析mybatis-config.xml文件的对象
private final XPathParser parser;
//标记<environments>标记的名称,默认读取default属性
private String environment;
//用来创建和缓存Reflector对象
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
}

解析方法:

//解析配置
public Configuration parse() {
//只解析加载一次
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//根节点是configuration
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}



//解析配置中各个节点
private void parseConfiguration(XNode root) {
try {
//1.解析<properties>节点
propertiesElement(root.evalNode("properties"));
//2.解析<typeAliases>节点
typeAliasesElement(root.evalNode("typeAliases"));
//3.解析<plugins>节点
pluginElement(root.evalNode("plugins"));
//4.解析<objectFactory>节点
objectFactoryElement(root.evalNode("objectFactory"));
//5.解析<objectWrapperFactory>节点
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//6.解析<settings>节点
settingsElement(root.evalNode("settings"));
//7.解析<environments>节点
environmentsElement(root.evalNode("environments"));
//8.解析<databaseIdProvider>节点
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//9.解析<typeHandlers>节点
typeHandlerElement(root.evalNode("typeHandlers"));
//10.解析<mappers>节点
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}

对应官方给出的配置项:



Mybatis配置各属性含义及赋值就不在这里赘述了。以解析<properties>节点为例,XMLConfigBuilder.propertiesElement()方法会解析<properties>节点并转化成Properties对象保存到XPathParser和Configuration的variables字段中。具体实现如下:

private void propertiesElement(XNode context) throws Exception {
//<properties resource="org/mybatis/example/config.properties">
// <property name="username" value="aaaaa"/>
// <property name="password" value="bbbbb"/>
//</properties>
if (context != null) {
//如果在这些地方,属性多于一个的话,MyBatis 按照如下的顺序加载它们:
//1.读取property属性。
//2.读取url或resource对应的属性,第19行指明二者不能同时配置。
//3.作为方法参数传递的属性最后被读取
//如果属性名称相同,后加载的值会覆盖前者
//1.XNode.getChildrenAsProperties函数方便得到孩子所有Properties
Properties defaults = context.getChildrenAsProperties();
//2.然后查找resource或者url,加入前面的Properties
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
//3.Variables也全部加入Properties
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}

其他大多数配置的加载过程跟上面过程相似,也比较好理解,鉴于篇幅原因建议大家看看源码,后面文章还会讲一下解析<mappers>节点,因为MyBatis初始化过程中还需要加载全部的映射配置。待续...



发布于: 2020 年 05 月 07 日 阅读数: 68
用户头像

杨家昌

关注

这是一位神秘人物 2020.05.06 加入

10年java老兵带新人通关,感兴趣的赶紧上车。

评论

发布
暂无评论
MyBatis 3 解析mybatis-config.xml配置