mybatis为什么这么写?
当我们在写mybatis配置文件的时候,可能会遇到这样的问题
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
这其实是mybatis在提示我们顺序配错了。那如果不用过idea的提示,我们应该怎么了解mybatis应该怎样去定义配置文件呢?
XMLConfigBuilder
在mybatis源码中能看到不少像XMLConfigBuilder
这样的类,并且他们都继承了BaseBuilder,他的作用是负责解析mybatis-config.xml配置文件的。
源码分析
public class XMLConfigBuilder extends BaseBuilder {
private boolean parsed; // 判断是否已经解析过mybatis-config.xml文件
// 用于解析配置文件的对象,这是由mybatis自己封装的一个对象,其底层还是使用了XPath(可以参考我上一篇文章)
private final XPathParser parser;
// 标识了<environment>(配置不同生产环境的不同配置)配置的名称,
private String environment;
// 负责创建和缓存Reflector对象(每一个对象都对应了一个类,以后会写文章仔细讲)
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
// 省略各种构造函数
public XMLConfigBuilder() {
}
// 解析mybatis-config.xml配置文件的入口
public Configuration parse() {
if (parsed) { // 判断是否已经解析过
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration")); // 解析<configuration>
return configuration;
}
// 通过这里我们就可以清楚为什么mybatis-config.xml根据怎么进行配置,为什么引用外部配置文件
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);
}
}
这里将解析每一个节点都封装成一个特定的方法。由于篇幅过大,以后会将每一个方法写成一篇文章方便查看。