MyBatis 3源码解析(一)
一、SqlSessionFactory 对象初始化
//加载全局配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//1.获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

1.调用SqlSessionFactoryBuilder的build(inputStream);方法,方法如下:
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
实际上调用如下方法;
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//XMLConfigBuilder是对mybatis的配置文件进行解析的类
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//1.调用当前类的parse() 方法,返回configuration。2.调用build方法,返回SqlSessionFactory
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.
}
}
}
- 首先传入全局配置文件的输入流,创建了XMLConfigBuilder对象。然后调用XMLConfigBuilder 的parse()方法。代码如下:
public Configuration parse() {
//判断Configuration是否解析过,Configuration是全局变量,只需要解析创建一次即可
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//调用下面的方法,parser.evalNode("/configuration")解析XML配置的configuration节点的内容,得到XNode对象
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
parser.evalNode(“/configuration”)是调用了XPathParser类的evalNode方法返回的是XNode对象。XNode对象保存了解析后的对应节点下的所有信息。
- 然后parseConfiguration(parser.evalNode("/configuration")); 方法,代码如下:
//根据root中存储的是configuration节点的内容
private void parseConfiguration(XNode root) {
try {
//设置settings配置
Properties settings = settingsAsPropertiess(root.evalNode("settings"));
//设置properties配置
propertiesElement(root.evalNode("properties"));
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"));
//设置mappers配置
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
可以看出parse的作用是解析mybatis-config.xml的configuration节点的内容,然后挨个赋值给configuration对象的属性;
- settingsElement(settings); 方法如下:将全局配置文件中所有结点的配置信息都设置到了configuration对象中
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));
- mapperElement(root.evalNode("mappers")); 方法,则是将是对SQL映射文件进行了解析。解析后将信息设置到了configuration对象中
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();
解析mapper映射文件代码如下:
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
resultMapElements(context.evalNodes("/mapper/resultMap"));
sqlElement(context.evalNodes("/mapper/sql"));
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
到这里 return build(parser.parse()); 就要返回了,build方法如下:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
返回的SqlSessionFactory 对象中封装了所有的配置信息。Configuration封装了所有配置文件的详细信息。
总结:把配置文件的信息解析并保存在Configuration对象中,返回包含了Configuration的DefaultSqlSession对象。
MyBatis 3源码解析(一)的更多相关文章
- MyBatis详细源码解析(上篇)
前言 我会一步一步带你剖析MyBatis这个经典的半ORM框架的源码! 我是使用Spring Boot + MyBatis的方式进行测试,但并未进行整合,还是使用最原始的方式. 项目结构 导入依赖: ...
- Mybatis SqlNode源码解析
1.ForEachSqlNode mybatis的foreach标签可以将列表.数组中的元素拼接起来,中间可以指定分隔符separator <select id="getByUserI ...
- Mybatis SqlSessionTemplate 源码解析
As you may already know, to use MyBatis with Spring you need at least an SqlSessionFactory and at le ...
- MyBatis 3源码解析(四)
四.MyBatis 查询实现 Employee empById = mapper.getEmpById(1); 首先会调用MapperProxy的invoke方法 @Override public O ...
- MyBatis 3源码解析(三)
三.getMapper获取接口的代理对象 1.先调用DefaultSqlSession的getMapper方法.代码如下: @Override public <T> T getMapper ...
- MyBatis 3源码解析(二)
二.获取SqlSession对象 1.首先调用DefaultSqlSessionFactory 的 openSession 方法,代码如下: @Override public SqlSession o ...
- mybatis源码解析1--前言
在开始分析mybatis源码之前,需要定一个目标,也就是我们不是为了读源码而去读,一定是带着问题去读,在读的时候去寻找到答案,然后再读码的同时整理总结,学习一些高级的编码方式和技巧. 首先我们知道my ...
- Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码
在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...
- Mybatis源码解析(一)(2015年06月11日)
一.简介 先看看Mybatis的源码结构图,Mybatis3.2.7版本包含的包共计19个,其他版本可能会少. 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为 ...
随机推荐
- 学习ASP.NET Core Razor 编程系列十五——文件上传功能(三)
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- 为什么要抛弃Pact?如何快速实现契约测试(CDC)
前言 在前几天的博客中,我转载了一篇文章,其中介绍了契约测试和pact是怎么实施的,的确很有帮助.但我经过研究,其实是pact本身也是有缺陷的,结合我近期在使用的服务型工具和我的实际情况,觉得实现契约 ...
- Tomcat 对 HTTP 协议的实现(上)
协议,直白的说就是存在一堆字节,按照协议指定的规则解析就能得出这堆字节的意义.HTTP 解析分为两个部分:解析请求头和请求体. 请求头解析的难点在于它没有固定长度的头部,也不像其他协议那样提供数据包长 ...
- javascript小记一则:今天在写VS2005——.NET程序时,写的一个JS图片示例案例
源码如下,如遇调试问题,可以找我解决: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &quo ...
- C#开发——网站应用微信登录开发
1. 在微信开放平台注册开发者账号,并有一个审核已通过的网站应用,并获得相对应的AppID和AppSecret,申请通过登陆后,方可开始接入流程. 2.微信OAuth2.0授权登录目前支持author ...
- int 与 Integer 的区别
int和Integer的区别 Integer是int的包装类,int则是java的一种基本数据类型 Integer变量必须实例化后才能使用,而int变量不需要 Integer实际是对象的引用,当new ...
- easyui表格排序
效果:点击DataGrid表格某个头部,进行升序或降序排序当前页: 问题:对应列设置 sortable:true 没有效果,刚开始以为是对应的列对应的数据库的字段类型有问题, 改动代码,使返回到前台 ...
- android WebView技术笔记(存储技术)
作为刚刚开始工作的新手程序猿,各种知识还不算熟练,所以将学习到的知识记录一下以免以后忘记. WebView加载h5的知识现在可以说非常的常用,通过加载h5的网页可以在不更新app的情况下来更新app的 ...
- android使用百度地图最新sdk5.0后后代码混淆时,地图无法显示闪退问题
描述:刚开始遇到这个问题我一步一步去排除,最后发现在初始化地图的时候,代码混淆就有问题了, 问题描述:当跳显示地图的页面APP闪退, 解决对比: 1:对于老版本百度sdk:代码混淆时语句: -libr ...
- appium+python搭建自动化测试框架_TestAPP框架(三)
Pycharm 创建 Project,搭建 APPTEST框架如下图: 1.框架功能 业务功能的封装 测试用例封装 测试包管理 截图处理 断言处理 日志获取 测试报告生成 数据驱动 数据配置 2. ...