说明

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. bzoj 1601 灌水

    题目大意: 决定把水灌到n块农田,农田被数字1到n标记 把一块土地进行灌水有两种方法,从其他农田饮水,或者这块土地建造水库 建造一个水库需要花费wi,连接两块土地需要花费Pij. 计算所需的最少代价 ...

  2. NodeJs函数式编程

    虽然标题是NodeJS函数式编程,但实际上NodeJS 是一个框架,不是一种语言,其采用的语言是 JavaScript.而JavaScript是一种典型的多范式编程语言,算不上是函数式语言,但它有函数 ...

  3. JavaGraphics类的绘图方法

    Graphics类提供基本绘图方法,Graphics类提供基本的几何图形绘制方法,主要有:画线段.画矩形.画圆.画带颜色的图形.画椭圆.画圆弧.画多边形.画字符串等. 1. 画线段:在窗口中画一条线段 ...

  4. DStream 转换操作----无状态转换

    DStream转换操作包括无状态转换和有状态转换. 无状态转换:每个批次的处理不依赖于之前批次的数据. 有状态转换:当前批次的处理需要使用之前批次的数据或者中间结果.有状态转换包括基于滑动窗口的转换和 ...

  5. 40. combo的displayField和valueField属性

    转自:https://xsl2007.iteye.com/blog/773464 下拉框combo可以设置displayField和valueField属性,这两个值值相当于Java中的map,一个键 ...

  6. 用vue-cli快速构建项目

    用vue-cli脚手架快速构建项目的过程:1.首先要在node的环境下安装: 1>安装node:https://nodejs.org/en/(带npm,但是npm太慢了,建议安装cnpm,cnp ...

  7. php使用163邮箱发送邮件

    email.class.php文件 <? class smtp { /* Public Variables */ var $smtp_port; var $time_out; var $host ...

  8. 9.28NOIP模拟题

    9.28NOIP模拟题 题目 哈 哈哈 哈哈哈 英文题目与子目录名 ha haha hahaha 单个测试点时间限制 1秒 1秒 1秒 内存限制 256M 128M 64M 测试点数目 10 10 1 ...

  9. P2258 子矩阵(dp)

    P2258 子矩阵 题目描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵. 例如,下面左图中选取第2.4行和第2.4 ...

  10. PHPExcel读取文件日期处理,含时分秒(Thinkphp)

    我们使用PHPExcel读取excel文件后发现,时间都是类似于这样的数字:41890.620138889,那么如何将它处理成我们想要的2014-09-08 14:53:00这样格式的日期呢,看代码: ...