mybatis源码分析(一)
mybatis 解析configuration中的properties
<configuration>
<properties>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
</configuration>
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
1.创建一个新的Configuration对象
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());//创建新的Configuration对象
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);**//这个是外部传入的属性**
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
public Configuration parse() {
if (parsed) { //已经解析过就直接抛出异常
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
2.parseConfiguration(parser.evalNode("/configuration")); 方法
parser.evalNode("/configuration") 这个是xnode解析节点
重点看parseConfiguration 这个
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties")); **//今天重点分析这段代码**
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(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);
}
}
- private void propertiesElement(XNode context) throws Exception {
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
Properties defaults = context.getChildrenAsProperties();//先读取属性文件的
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) { //resource 和url不能同时指定 否则抛出异常
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));
}
//通过url或resource传进去的会把配置文件定义的覆盖掉
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
//通过SqlSessionFactory的build方法传入的会把前面的两种都覆盖掉
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
4.总结
1.properties 标签resource和url只能有一个
2.properties优先级从低到高 标签里定义的->通过resource或url定义的->通过SqlSessionFactory的build方法传入的
扩展
从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值(这个用的很少)
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${username:ut_user}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->
</dataSource>
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- 修改默认值的分隔符 -->
</properties>
这个在之后的文章里再行解释