说明

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. AngularJS2.0 hello world例子——引入这么多额外的依赖库真是很忧伤啊

    初识Angular2 写一个Angular2的Hello World应用相当简单,分三步走: 1. 引入Angular2预定义类型 import {Component,View,bootstrap} ...

  2. JSP页面规格化

    http://doc.okbase.net/%E4%BA%BA%E7%94%9F%E9%9A%BE%E5%BE%97%E7%B3%8A%E6%B6%82/archive/123084.html htt ...

  3. B1068 [SCOI2007]压缩 区间dp

    这个题我状态想对了,但是转移错了...dp的代码难度都不大,但是思考含量太高了..不会啊,我太菜了. 其实这个题就是一个正常的区间dp,中间多了一个特判的转移就行了. 题干: Description ...

  4. DVB-subtitle解析流程浅

    DTV包含SUBTITLE和TTX. PMT中分别有不同的描述符对应,如下图的TTX descripter=0x56.语言ISO-639="fin" subtitle descri ...

  5. JSP-Runoob:JSP 自动刷新

    ylbtech-JSP-Runoob:JSP 自动刷新 1.返回顶部 1. JSP 自动刷新 想象一下,如果要直播比赛的比分,或股票市场的实时状态,或当前的外汇配给,该怎么实现呢?显然,要实现这种实时 ...

  6. windows 7系统下安装SQL Server 2005图文教程

    由于工作需要,今天要在电脑上安装SQL Server 2005.以往的项目都是使用Oracle,MS的数据库还真的没怎么用过,安装Oracle已经轻车熟路,但装SQL Server好像还有点小麻烦,所 ...

  7. C. Unusual Product(cf)

    http://codeforces.com/problemset/problem/405/C 题意: 给出一个n*n的矩阵,有q个操作,输入3时,输出A ,A等于第i行乘以第i列的对应元素的和(mod ...

  8. Android点9图的运用

    在Android UI设计开发中,我们经常会用到一些图标.图片来做背景等. 相信很多同学都会遇到一个问题,就是我们让美工做好一张图,一个图标,呃,看起来挺好看的,但是放进app中,扩大或缩小.在不同分 ...

  9. Python基础类型(二) str 字符串

    字符串str ' ' 字符串+ 都是字符串的时候才能相加 a = 'alex' b = 'wusir' print(a+b) #字符串拼接 字符串* 字符串和数字相乘 a = 6 b = 'alex' ...

  10. warning: remote HEAD refers to nonexistent ref, unable to checkout

    今天使用git clone时候 提示 warning: remote HEAD refers to nonexistent ref, unable to checkout 经过测试解决办法如下 git ...