Mybatis配置文件之属性配置元素解析
1. 概述
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properties)信息。文档的顶层结构如下:
在这篇文章中,我们首先来看下元素,这个元素从上篇文章中可以看到是最先被解析的,设置的属性值将会被其他元素所使用。
2. properties
属性的设置有三种方式:通过配置文件中的元素的子元素设置、通过properties的resource或者url属性传入文件、通过初始化的时候以代码的方式传入。
2.1 以子元素方式设置
之前的配置文件中元素中设置了数据库的驱动、连接字符串还有账号密码等信息我们是通过外部文件的方式传入的,这里通过设置来进行设置,如下所示:
<properties>
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/my_mybatis?characterEncoding=utf-8"/>
<property name="username" value="yhl"/>
<property name="password" value="1234"/>
</properties>
如上代码这样,我们就在需要配置的地方统一到了元素中,便于统一管理。
2.2 通过properties元素的resource或者url属性引入外部文件
我们之前设置dataSource的方式就是使用的这种方式,如下代码:
使用配置文件的方式,可以使得一次配置在多个地方重复使用,不需要在不同的项目中CTRL+C和CTRL+V了。
2.3 在通过在初始化的时候,以代码的方式传入Properties类实例
接下来我们修改下之前的MybatisUtils文件,添加一下构造Propertie实例的代码:
private static Properties buildInitProperties(){
Properties properties = new Properties();
properties.put("driver", "com.mysql.jdbc.Driver");
properties.put("url", "jdbc:mysql://localhost:3306/my_mybatis?characterEncoding=utf-8");
properties.put("username", "yhl");
properties.put("password", "1234");
return properties;
}
然后修改下getSessionFactory方法,传入构造的Properties实例,如下:
private static SqlSessionFactory getSessionFactory() {
SqlSessionFactory sessionFactory = null;
String resource = "mybatis-config.xml";
try {
sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource),buildInitProperties());
} catch (IOException e) {
e.printStackTrace();
}
return sessionFactory;
}
从上可以看出,在创建SqlSessionFactory的时候,人为写代码传入了一套属性配置。
上面三种方式都可以实现相同的功能,那就是给mybatis初始化的时候设置一系列的属性值以供使用。但是这三者又有什么区别呢?接下来我们就通过查看源码来详细了解下三种方式的区别。
3. Mybatis设置Properties源码解析
mybatis设置properties是在XMLConfigBuilder中的propertiesElement方法中实现的,下面是此方法的源码:
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) {
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));
}
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
通过查看源码,一个直观的感觉就是这三种配置是有优先级关系的且不同方式配置的配置项是可以并存的,优先级次序如下:第三种方式>第二种方式>第一种方式。即如果三种方式都配置了同一个配置项,那么优先级高的配置方式的配置值生效。这主要还是因为mybats的源码解析过程导致的。
从代码看,元素的resource属性和url属性是不能同时设置的,否则会报异常。同时,解析的时候是先解析的标签元素,而后从resource或者url指定的配置文件开始读取配置,如果之前有了相同的配置项则进行覆盖,如果没有则进行添加。在这之后,开始判断是否有第三种方式的属性配置,如果有,则将相关配置添加到之前的属性集合中,如果存在同名的配置也进行覆盖。这样的逻辑也是导致为什么会有优先级的直接原因。