说明

mybatis初始化过程 就是解析xml到封装成Configuration对象 供后续使用

SqlSessionFactoryBuilder

代码例子

     SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder
.build(ClassLoader.getSystemResourceAsStream("mybatis.xml"));

说明

通过build将流交给XMLConfigBuilder处理  XMLConfigBuilder通过parse解析XML封装到Configuration  然后SqlSessionFactoryBuilder 创建DefaultSqlSessionFactory 并将解析的Configuration 设置到DefaultSqlSessionFactory对象的属性

源码

    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//将流传入XMLConfigBuilder
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//parser.parse() 解析xml和mapper文件 封装成Configuration并返回
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset(); try {
inputStream.close();
} catch (IOException var13) {
;
} } return var5;
} public SqlSessionFactory build(Configuration config) {
//初始化Configuration
return new DefaultSqlSessionFactory(config);
}

XMLConfigBuilder

说明

负责解析指定xml并封装成Configuration 对象

源码

public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
//获得根节点configuration
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
} private void parseConfiguration(XNode root) {
try {
//解析settings并封装成Properties
Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
//解析properties
this.propertiesElement(root.evalNode("properties"));
this.loadCustomVfs(settings);
//解析typeAliases
this.typeAliasesElement(root.evalNode("typeAliases"));
//解析plugins
this.pluginElement(root.evalNode("plugins"));
//解析objectFactory
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectionFactoryElement(root.evalNode("reflectionFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}

注意root.evalNode为mybatis封装的解析xml的工具类 root为XNode对象 感兴趣可以查看

mapper解析过程

mapperElement(root.evalNode("mappers"))

    private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
Iterator i$ = parent.getChildren().iterator(); while(true) {
while(i$.hasNext()) {
XNode child = (XNode)i$.next();
String resource;
//2种配置选择 <mappers><mapper resource="ClassesMapper.xml"></mapper><mapper class=""></mapper><package name="com.liqiang.mapper"/></mappers>
if ("package".equals(child.getName())) {
resource = child.getStringAttribute("name");
this.configuration.addMappers(resource);
} else {
resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
XMLMapperBuilder mapperParser;
InputStream inputStream;
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
inputStream = Resources.getResourceAsStream(resource);
//得到对应的mapper.xml文件 交给XmlMapperBuilder解析 并将结果封装到configuration
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
inputStream = Resources.getUrlAsStream(url);
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
mapperParser.parse();
} else {
if (resource != null || url != null || mapperClass == null) {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
} Class<?> mapperInterface = Resources.classForName(mapperClass);
this.configuration.addMapper(mapperInterface);
}
}
} return;
}
}
}

XMLMapperBuilder

解析源码

 private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace != null && !namespace.equals("")) {
this.builderAssistant.setCurrentNamespace(namespace);
this.cacheRefElement(context.evalNode("cache-ref"));
this.cacheElement(context.evalNode("cache"));
this.parameterMapElement(context.evalNodes("/mapper/parameterMap"));
this.resultMapElements(context.evalNodes("/mapper/resultMap"));
this.sqlElement(context.evalNodes("/mapper/sql"));
this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} else {
throw new BuilderException("Mapper's namespace cannot be empty");
}
} catch (Exception var3) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + var3, var3);
}
}

图解

图片来源:https://my.oschina.net/zudajun/blog/668738

最终这些标签都会以对象的形式封装起来以map格式保存到configuration 的map里面key为id如:

public class Configuration {
protected final Map<String, MappedStatement> mappedStatements;
protected final Map<String, Cache> caches;
protected final Map<String, ResultMap> resultMaps;
protected final Map<String, ParameterMap> parameterMaps;
protected final Map<String, KeyGenerator> keyGenerators;
}

其他

typeAlias package扫描

<typeAliases>
<typeAlias alias="Student" type="com.mybatis3.domain.Student" />
<typeAlias alias="Teacher" type="com.mybatis3.domain.Teacher" />
<package name="com.mybatis3.domain" />
</typeAliases>

XMLConfigBuilder

 private void typeAliasesElement(XNode parent) {
if (parent != null) {
Iterator i$ = parent.getChildren().iterator(); while(i$.hasNext()) {
XNode child = (XNode)i$.next();
String alias;
//如果是package反射获得类下面的所有类型 registerAlias
if ("package".equals(child.getName())) {
alias = child.getStringAttribute("name");
this.configuration.getTypeAliasRegistry().registerAliases(alias);
} else {
alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type"); try { Class<?> clazz = Resources.classForName(type);
if (alias == null) {
//如果没有指定别名 内部会读取类上面的Alias注解的value为别名
this.typeAliasRegistry.registerAlias(clazz);
} else {
//注册
this.typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException var7) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + var7, var7);
}
}
}
} }

简写和全名称都能执行sql原理

表现形式

Student std  = sqlSession.selectOne("findStudentById", 1);
Student std = sqlSession.selectOne("com.mybatis3.mappers.StudentMapper.findStudentById", 1);

原理

mybatis重写保存Statement的Configuration.StrictMap

this.mappedStatements = new Configuration.StrictMap("Mapped Statements collection");
this.caches = new Configuration.StrictMap("Caches collection");
this.resultMaps = new Configuration.StrictMap("Result Maps collection");
this.parameterMaps = new Configuration.StrictMap("Parameter Maps collection");
this.keyGenerators = new Configuration.StrictMap("Key Generators collection");】
    public V put(String key, V value) {
if (this.containsKey(key)) {
throw new IllegalArgumentException(this.name + " already contains value for " + key);
} else {
//判断是否是配的全名称
if (key.contains(".")) {
//获得简写形式
String shortKey = this.getShortName(key);
//判断是否存在
if (super.get(shortKey) == null) {
//如果不存在直接放进去
super.put(shortKey, value);
} else {
//如果重复 则保存一个占位符 get的时候判断值是这个占位符 则抛错
super.put(shortKey, new Configuration.StrictMap.Ambiguity(shortKey));
}
}
//原始配置保存
return super.put(key, value);
}
}
public V get(Object key) {
V value = super.get(key);
if (value == null) {
throw new IllegalArgumentException(this.name + " does not contain value for " + key);
//如果是Ambiguity 则抛错
} else if (value instanceof Configuration.StrictMap.Ambiguity) {
throw new IllegalArgumentException(((Configuration.StrictMap.Ambiguity)value).getSubject() + " is ambiguous in " + this.name + " (try using the full name including the namespace, or rename one of the entries)");
} else {
return value;
}
}
}

mybatis源码阅读-初始化过程(七)的更多相关文章

  1. mybatis源码阅读-初始化六个工具(六)

    六个基本工具图集 图片来源:https://my.oschina.net/zudajun/blog/668596 ObjectFactory 类图 接口定义 public interface Obje ...

  2. Mybatis源码阅读-配置文件及映射文件解析

    Mybatis源码分析: 1.配置文件解析: 1.1源码阅读入口: org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(); 功能:解析全局配置文 ...

  3. mybatis源码阅读-MappedStatement各个属性解析过程(八)

    调用方 类org.apache.ibatis.builder.xml.XMLMapperBuilder private void configurationElement(XNode context) ...

  4. mybatis源码阅读心得

    第一天阅读源码及创建时序图.(第一次用prosson画时序图,挺丑..) 1.  调用 SqlSessionFactoryBuilder 对象的 build(inputStream) 方法: 2.   ...

  5. mybatis源码阅读(动态代理)

    这一篇文章主要是记录Mybatis的动态代理学习成果,如果对源码感兴趣,可以看一下上篇文章  https://www.cnblogs.com/ChoviWu/p/10118051.html 阅读本篇的 ...

  6. Mina源码阅读笔记(七)—Mina的拦截器FilterChain

    Filter我们很熟悉,在Mina中,filter chain的用法也类似于Servlet的filters,这种拦截器的设计思想能够狠轻松的帮助我们实现对资源的统一处理.我们先大致连接下mina中的f ...

  7. Mybatis源码阅读 之 玩转Executor

    承接上篇博客, 本文探究MyBatis中的Executor, 如下图: 是Executor体系图 本片博客的目的就是探究如上图中从顶级接口Executor中拓展出来的各个子执行器的功能,以及进一步了解 ...

  8. mybatis源码阅读-Transaction和TransactionFactory(四)

    Transaction 类图 接口定义 public interface Transaction { Connection getConnection() throws SQLException; v ...

  9. mybatis源码阅读-SqlSessionFactory和SqlSession(三)

    说明 读了3遍:https://my.oschina.net/zudajun/blog/665956 现在统一整理成笔记 并跟着源码一行一行调试 统一整理起来 SqlSession 接口定义 publ ...

随机推荐

  1. 【POJ 3263】 Tallest Cow

    [题目链接] http://poj.org/problem?id=3263 [算法] 若A和B两头牛可以互相看见,那么说明中间的牛的高度都至少比它们少1,因此,我们可以引入一个差分数组c 对于每组关系 ...

  2. ubuntu系统快捷键设置

    1.打开'系统设置' 2.点击键盘 3.选择快捷键,查看和修改对应的快捷键.

  3. [Swift通天遁地]九、拔剑吧-(13)创建页面的景深视差滚动效果

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  4. Tornado异步模式

    先介绍下背景:由于工作需要,前段时间又写了一段爬虫去获取和更新一些数据.之前爬虫主要用Scrapy框架批量爬取一些页面数据,或者用Gevent调用目标站点的接口.偶然看到了Tornado,听说这个框架 ...

  5. nginx + php-fpm 运行原理

    一.关于nginx 1.1 简单认知 我们都知道nginx 是web服务器. 也知道 用户访问时通过ip和端口访问 nginx. 那么nginx 是如何 通过php 获取数据并返回数据的呢? 1.2 ...

  6. 51nod 1222 莫比乌斯反演

    思路: yhx找的反演题 题解已经烂大街了 #pragma GCC optimize("O3") //By SiriusRen #include <bits/stdc++.h ...

  7. PKUSC2017 游记 密码:blog密码

    退役之前,写点破事乐呵乐呵 省选滚大粗   报了PKU和THU的SC  果然THU直接审核不通过... 于是就来到了PKU   滚粗狗就又续命几天. Day1 上午考数学 喜闻乐见啥都不会 出来一对题 ...

  8. 在下载jar包时,要有三个包,分别为使用的把class、查看文档的api、查看源代码的资源包

    字节码包: spring-webmvc-4.1.6.RELEASE.jar 文档包:    spring-webmvc-4.1.6.RELEASE-javadoc.jar 资源包:    webmvc ...

  9. [ SCOI 2005 ] 最大子矩阵

    \(\\\) \(Description\) 给出一个\(N\times M\)的有权矩阵,选出其中\(K\)个互不重叠的子矩阵,使得这\(K\)个子矩阵的权值和最大. \(N\in [1,100]\ ...

  10. 1B课程笔记分享_StudyJams_2017

    课程1B 概述 课程1B主要讲解了Android UI的ViewGroups(视图组).LinearLayout(线性布局).RelativeLayout(相对布局),Portrait Mode(竖屏 ...