myBatis源码之XMLConfigBuilder
XMLConfigBuilder是对mybatis的配置文件进行解析的类,会对myabtis解析后的信息存放在Configuration对象中,Configuration对象会贯穿整个mybatis的执行流程,为mybatis的执行过程提供各种需要的配置信息。
/**
* @author Clinton Begin
*/
public class XMLConfigBuilder extends BaseBuilder {
private boolean parsed;
private XPathParser parser;
private String environment;
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;
}
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//mybatis的配置文件的根节点是configuration,从根节点开始解析配置文件
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//解析子节点properties
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
//解析子节点typeAliases 别名
typeAliasesElement(root.evalNode("typeAliases"));
//解析子节点plugins 插件
pluginElement(root.evalNode("plugins"));
//解析子节点objectFactory mybatis为结果创建对象时都会用到objectFactory
objectFactoryElement(root.evalNode("objectFactory"));
//解析子节点objectWrapperFactory
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//解析settings定义一些全局性的配置
settingsElement(root.evalNode("settings"));
//解析environments 可以配置多个运行环境,但是每个SqlSessionFactory 实例只能选择一个运行环境
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
//解析databaseIdProvider MyBatis能够执行不同的语句取决于你提供的数据库供应商。许多数据库供应商的支持是基于databaseId映射
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//解析typeHandlers 当MyBatis设置参数到PreparedStatement 或者从ResultSet 结果集中取得值时,就会使用TypeHandler 来处理数据库类型与java 类型之间转换
typeHandlerElement(root.evalNode("typeHandlers"));
//解析mappers 主要的crud操作都是在mappers中定义的
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
//类别名解析
private void typeAliasesElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//如果子节点是package,那么就获取package节点的name属性
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
//如果子节点是typeAlias节点,那么就获取alias属性和type的属性
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
//通过type的值来加载获得类
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
//typeAliasRegistry会进行别名注册
typeAliasRegistry.registerAlias(clazz);
} else {
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
//插件元素解析
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
//对象工厂元素解析
private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties properties = context.getChildrenAsProperties();
ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
factory.setProperties(properties);
configuration.setObjectFactory(factory);
}
}
//对象打包工厂元素解析
private void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
configuration.setObjectWrapperFactory(factory);
}
}
//
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);
}
}
//配置元素解析
private void settingsElement(XNode context) throws Exception {
if (context != null) {
Properties props = context.getChildrenAsProperties();
// Check that all settings are known to the configuration class
MetaClass metaConfig = MetaClass.forClass(Configuration.class);
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).");
}
}
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
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"), true));
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.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.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setLogImpl(resolveClass(props.getProperty("logImpl")));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
}
}
//环境元素解析
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
//解析databaseIdProvider MyBatis能够执行不同的语句取决于你提供的数据库供应商。许多数据库供应商的支持是基于databaseId映射
private void databaseIdProviderElement(XNode context) throws Exception {
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
String type = context.getStringAttribute("type");
if ("VENDOR".equals(type)) type = "DB_VENDOR"; // awful patch to keep backward compatibility
Properties properties = context.getChildrenAsProperties();
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
databaseIdProvider.setProperties(properties);
}
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
configuration.setDatabaseId(databaseId);
}
}
//事务配置解析,获得事务工厂(JDBC和MANAGED两种)
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
//数据源解析获得数据源工厂
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
//类型控制元素解析,数据库数据类型和Java数据类型的解析
private void typeHandlerElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
} else {
String javaTypeName = child.getStringAttribute("javaType");
String jdbcTypeName = child.getStringAttribute("jdbcType");
String handlerTypeName = child.getStringAttribute("handler");
Class<?> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
//mapper元素解析,获得各种crud操作或者配置文件
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
private boolean isSpecifiedEnvironment(String id) {
if (environment == null) {
throw new BuilderException("No environment specified.");
} else if (id == null) {
throw new BuilderException("Environment requires an id attribute.");
} else if (environment.equals(id)) {
return true;
}
return false;
}
}
myBatis源码之XMLConfigBuilder的更多相关文章
- Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)
在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到 代码:XMLConfigBuilder parser = new XMLConfigBuilder(read ...
- MyBatis源码分析-MyBatis初始化流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- MyBatis源码分析(2)—— Plugin原理
@(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...
- 深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)
上篇文章<深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)>我们通过对mybatis源码的简单分析,可看出,在mybatis配置文件中,在configuration根 ...
- MyBatis源码解读(1)——SqlSessionFactory
在前面对MyBatis稍微有点了解过后,现在来对MyBatis的源码试着解读一下,并不是解析,暂时定为解读.所有对MyBatis解读均是基于MyBatis-3.4.1,官网中文文档:http://ww ...
- 【MyBatis源码分析】select源码分析及小结
示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...
- Spring mybatis源码篇章-MybatisDAO文件解析(一)
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-SqlSessionFactory 加载指定的mybatis主文件 Mybatis模板文件,其中的属性 ...
- mybatis源码分析(一)
mybatis源码分析(sqlSessionFactory生成过程) 1. mybatis框架在现在各个IT公司的使用不用多说,这几天看了mybatis的一些源码,赶紧做个笔记. 2. 看源码从一个d ...
- Spring mybatis源码学习指引目录
前言: 分析了很多方面的mybatis的源码以及与spring结合的源码,但是难免出现错综的现象,为了使源码陶冶更为有序化.清晰化,特作此随笔归纳下分析过的内容.博主也为mybatis官方提供过pul ...
随机推荐
- Microsoft Dynamics CRM 2011 当您在 大型数据集上执行 RetrieveMultiple 查询很慢的解决方法
症状 当您在 Microsoft Dynamics CRM 2011 年大型数据集上执行 RetrieveMultiple 查询时,您会比较慢. 原因 发生此问题是因为大型数据集缓存 Retrieve ...
- Android简易实战教程--第十话《模仿腾讯手机助手小火箭发射详解》
之前对系统自带的土司的源码做了简要分析,见博客:点击打开链接 这一篇给一个小案例,自定义土司,模拟腾讯卫士的小火箭发射.如果想要迅速看懂代码,建议先去看一下上篇介绍点击打开链接 首先,定义一个服务,在 ...
- Shell在大数据时代的魅力:从一道百度大数据面试题想到的点滴
对于在Linux下开发的同学来说,Shell可以说是一种基本功. 对于运维的同学来说,Shell可以说是一种必备的技能,而且应该要非常熟练的书写Shell.对于Release Team,软件配置管理的 ...
- 【shell脚本】ftp自动上传mysql备份文件
上一篇中 mysql每日备份shell脚本 给出了使用mysqldump备份到本地的脚本,接着下面是利用ftp把备份文件传输到远程服务器的脚本. 当然也可以用scp,rsync等等方案. #!/bin ...
- javascript之JSON引入
JSON: JavaScript Object Notation JavaScript 对象表示法. 由于现在很多在服务器获取数据,很多都涉及json数据格式,因此学习json非常有必要. * 语 ...
- Caffe框架,了解三个文件
不知道从什么时候开始,Deep Learning成为了各个领域研究的热点,也不知道从什么时候开始,2015CVPR的文章出现了很多Deep Learning的文章,更不知道从什么时候开始,三维重建各个 ...
- Django介绍、安装配置、基本使用、Django用户注册例子
Django介绍 Django 是由 Python 开发的一个免费的开源网站框架,可以用于快速搭建高性能,优雅的网站 DjangoMTV的思想 没有controller ...
- Linux Shell -- 无网不利
这篇文章中我介绍几个非常实用的和网络相关的命令 一.ifconfig 这个命令在Windows下被"翻译为ipconfig",它用于显示网络接口,子网掩码等详细信息. 注:在每个系 ...
- Cocos2d中update与fixedUpdate的区别(四)
关于fixedUpdate:方法的目的 现在,想象一下在小球飞行的位置1到8之间有一个移动的平台: 该平台不停地上升和下降.有些时候小球可以不碰到而飘过平台,有些时候小球会和平台发生碰撞: 这表示小球 ...
- Mac OS X 10.8.4下面XZ Utils(*.tar.xz)压缩解压缩命令工具的安装
主要参考:http://bbs.chinaunix.net/thread-3610738-1-1.html 现在很多找到的软件都是tar.xz的格式的,xz 是一个使用 LZMA压缩算法的无损数据压缩 ...