一、加载配置文件
String resource = "org/mybatis/example/Configuration.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
二、 解析配置xml,生成配置类
将配置资源文件读取到Reader,然后传递构建,构建的时候,可以见SqlSessionFactoryBuilder里面有不同的方法,
主要是支持参数方式传递环境元素和属性参数,最后归结还是到下面这个方法:
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) {
// Intentionally ignore. Prefer previous error.
}
}
}
可以看到是使用XMLConfigBuilder将配置文件信息,转换成Configuration,主要看parser.parse()
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
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节点,然后分别处理不同的标签:
propertiesElement(root.evalNode("properties"));//属性文件,数据库驱动配置?
typeAliasesElement(root.evalNode("typeAliases"));//类型方言,用于结果转换
pluginElement(root.evalNode("plugins"));//插件,可以配置不同时机的拦截器
objectFactoryElement(root.evalNode("objectFactory"));//对象工厂,可以配置返回对象属性
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings")); //全局变量,缓存,延迟加载等配置
environmentsElement(root.evalNode("environments")); //环境变量,
根据配置构建数据源工厂,事务工厂
databaseIdProviderElement(root.evalNode("databaseIdProvider"));//数据库提供标识ID,多数据库兼容的时候用到
typeHandlerElement(root.evalNode("typeHandlers")); //类型处理器,主要是对结果集,类型转换处理
mapperElement(root.evalNode("mappers"));//不同的mapper dao处理
三、mapperElement处理
提供多种方式加载mapper文件:package、resource、url、mapperClass
package,mapperClass直接加载mapper class,提供了注解方式加载配置信息。
resource、url,通过读取资源文件的方式加载mapper,最终加载所有配置文件后,还是转换成mapperClass方式加载。
也就是configuration的addMapper,这里面的逻辑就是注册mapper。
mapperRegistry.addMapper,里面会对mapper class做一次注解配置加载处理,具体见MapperAnnotationBuilder
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
不同加载方式最终的结果是得到注册所有的mapper接口类的代理工厂类 MapperProxyFactory
配置加载基本完毕,主要配置全局参数,环境变量,处理器。