说明

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. Codeforces--618A--Slime CombiningCrawling(数学)

     Slime CombiningCrawling in process... Crawling failed Time Limit:2000MS     Memory Limit:262144KB ...

  2. JAVA Swing 组件演示***

    下面是Swing组件的演示: package a_swing; import java.awt.BorderLayout; import java.awt.Color; import java.awt ...

  3. Factstone Benchmark(数学)

    http://poj.org/problem?id=2661 题意:Amtel在1960年发行了4位计算机,并实行每十年位数翻一番的策略,将最大整数n作为改变的等级,其中n!表示计算机的无符号整数(n ...

  4. 基于Spark Streaming预测股票走势的例子(一)

    最近学习Spark Streaming,不知道是不是我搜索的姿势不对,总找不到具体的.完整的例子,一怒之下就决定自己写一个出来.下面以预测股票走势为例,总结了用Spark Streaming开发的具体 ...

  5. 个人微信二次开发API接口

    通过这个API接口可以做什么? 通过我们提供的API接口您可以开发: 工作手机(如:X创,X码,XX管家等) 微信群讲课软件(如:讲课X师,一起X堂等) 微信社群管理软件(如:小X管家,微X助手等) ...

  6. C# 工厂单例

     public class BusinessFactory    {        private static BusinessFactory instance = null;        pri ...

  7. Kafka详解与总结(四)

    Kafka消息分发和消费者push.pull机制 1. 消息分发 Producer客户端负责消息的分发 kafka集群中的任何一个broker都可以向producer提供metadata信息,这些me ...

  8. c/c++ 参数传递 - 数组

    对于函数参数中的数组类型:传递的是数组地址,可以理解成传递的是对数组的引用.不是值传递,这是由C/C++函数实现机制决定的.一下三种函数生命完全等价: void func(int array[10]) ...

  9. Jenkins-SVN + Maven + Docker

    第1步:安装插件 Subversion Plug-inMaven Integration pluginCloudBees Docker Build and Publish pluginDeploy t ...

  10. C# 文件操作【转】

    本文也收集了目前最为常用的C#经典操作文件的方法,具体内容如下:C#追加.拷贝.删除.移动文件.创建目录.递归删除文件夹及文件.指定文件夹下面的所有内容copy到目标文件夹下面.指定文件夹下面的所有内 ...