mybatis之Configuration解析
Posted 我爱看明朝
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis之Configuration解析相关的知识,希望对你有一定的参考价值。
mybatis之Configuration解析
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置属性,可以在整个配置文件中用来替换需要动态配置的属性值 -->
<properties>
<property name= "" value "">
</properties>
<!-- 这是mybatis中极为重要的调整,它会改变mybatis的运行时行为, name不能自己定义mybatis有内置的name -->
<settings>
<setting name = "xxxx" value="" />
</settings>
<!-- 类型别名,可以为java类型设置一个缩写名字,仅用于xml中,意在降低冗余的书写 -->
<typeAliases>
<typeAlias alias = "xxx" type= "xx.xxx.xx" >
</typeAliases>
<!-- 自定义的类型处理器 -->
<typeHandlers>
<typeHandler handler = "xxxx" />
</typeHandler>
<!-- 自定义对象工厂, mybatis通过使用对象工厂,在获取结果集用来实例化对象 -->
<objectFactory type = "xxxx">
<!-- 可选 -->
<property name = "xxx" value = "xxx" />
</objectFactory>
<!-- 自定义插件 -->
<plugins>
<plugin interceptor = "xxxx">
<property name = "" value = "">
</plugin>
</plugins>
<!-- 环境类型 -->
<environments default = "dev">
<environment id = "dev">
<transactionManager type = "JDBC" >
<properyt name = "..." vlaue= "...">
</transactonManager>
<dataSource type= "POOLED">
<property name= "..." value = "...">
</dataSource>
</envitonment>
</environments>
<!-- 数据库厂商标识 -->
<databaseIdProvider type = "DB_VENDOR" >
<property name = "..." value = "...">
</databaseIdProvider>
<!-- mappers映射器 -->
<mappers>
<mapper resource = "xxxx" />
<mapper url = "xxx" />
<package name = "xxxx">
</mappers>
</configuration>
解析configuration的方法在XmlConfigurationBuilder中
public class XMLConfigBuiler extends BaseBuilder {
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);
}
}
}
configuration总览
properties
在获取sqlSessionFactory传入properties属性的源码分析
// 1. 获取到了SqlSessionFactory传入properties, properties设置配置key和value
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, properties);
// 2. 调用方法: build(InputStream inputStream, String environment, Properties properties), 行为类是重载方法方式
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
class public SqlSesstionFactoryBuilder {
//3. 实际调用的方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
}
public class XMLConfigBuilder extends BaseBuilder {
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
// 方法传入的参数存放入Configuration的variables
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
}
从xml文件读取properties属性
<configuration>
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
</configuration>
//XMLConfigBuilder
propertiesElement(root.evalNode("properties"));
//按照顺序加载属性
public class XMLConfiguration extends BaseBuilder {
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
// 1.解析出从xml中配置的属性
Properties defaults = context.getChildrenAsProperties();
//2.properties 可以配置resources或url任意属性(二者只能选其一)
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.");
}
// Properties.putAll方法的底层是往HashTable中放key和value,同名key会覆盖值。
//3. 如果有设置resource或url属性并且有值,则覆盖xml中的属性配置
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
//4. 如果在获取sqlSessionFactory传入properties属性,则覆盖上面两步的属性值
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
//更新configuration的variables
configuration.setVariables(defaults);
}
}
}
从上面源码我们得知Mybatis加载属性的顺序是:
1.首先读取xml在properties元素内指定的属性
2.根据properties中的属性resource或url读取,并覆盖上面的同名属性
3.最后读取方法参数传递的属性,并覆盖之前读取过的同名属性
从源码中学到的编码小技巧
根据XmlConfiguration的构造器的实现,我们可以学到复用重载方法
class public XMLConfigBuilder {
public XMLConfigBuilder(Reader reader) {
this(reader, null, null);
}
public XMLConfigBuilder(Reader reader, String environment) {
this(reader, environment, null);
}
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
public XMLConfigBuilder(InputStream inputStream) {
this(inputStream, null, null);
}
public XMLConfigBuilder(InputStream inputStream, String environment) {
this(inputStream, environment, null);
}
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
// 根据缺省参数来重载出不同的构造器
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
}
settings
当在settings中设置了属性的值,它会改变Configuration中指定属性的值,这会改变Mybatis的运行行为。
Properties settings = settingsAsProperties(root.evalNode("settings"));
public class XMLConfiBuilder extends BaseBuilder {
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
Properties props = context.getChildrenAsProperties();
//检查settings配置的属性是否存在于Configuration的属性
//使用mybatsi封装的反射方法
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
for (Object key : props.keySet()) {
if (!metaConfig.hasSetter(String.valueOf(key))) {
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
return props;
}
//根据读取到的Settings配置设置属性值,没有的则设置默认值
private void settingsElement(Properties props) throws Exception {
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.以上是关于mybatis之Configuration解析的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis之Configuration初始化(配置文件.xml的解析)