type
status
date
slug
summary
tags
category
icon
password
😀
这里写文章的前言: 一个简单的开头,简述这篇文章讨论的问题、目标、人物、背景是什么?并简述你给出的答案。
可以说说你的故事:阻碍、努力、结果成果,意外与转折。
 

📝 MyBatis 的工程流程分析

MyBatis 是我们在学习Java框架,也就是学习完JavaWeb的知识后,要学习到的一个ORM的框架. 我也是学习&使用过后,再次对源码进行阅读的. 所以这篇文章记录 MyBatis 的一个 work flow.
有兴趣的同学,可以clone下来看看.
 

代码案例

先放上案列的代码, 然后我们可以挨个的分析
 
这里说下大致流程:
  • 使用 Resources 来读取 mybatis-config.xml配置文件, 如果该文件不存在或者读取出来 InputStream 是 null 的话,程序就会抛出 IOException 的错误来.
  • 读取配置没有问题,来到 new SqlSessionFactoryBuilder().build(io) 来构建出一个 SqlSessionFactory 来, 这里构建出来的 SqlSessionFactory 肯定是有已经讲配置文件给全部加载进去了的.
  • SqlSessionFactory.openSession() 从 SqlSessionFactory 中获取一次会话, 然后可以从会话中获取出接口(BlogMapper)来,这里是不是有点好奇,明明这就是一个接口,也没有实现类,怎么就可以get出一个接口对象来?获取出接口来,然后就可以调用接口中的方法, 根据id查询出数据来.
可以看到,根据从官网写的一个列子,从表面来看,代码量并不是很多. 所以接下来点去源码,去跟进源码中的每个方法,到底做了些什么事情.

读取配置文件

 
org.apache.ibatis.io.Resources (Class).
可以看到MyBatis源码还写了一个 ClassLoader的包装类,通过ClassLoaderWrapper包装类来讲配置文件转化为InputSream.
如果返回的InputStream是null,就会抛出IOException来.
 
于是我们接着看 ClassLoaderWrapper 是怎么 读取配置文件 & 转化为 InputStream 流的.
 
至此,MyBatis读取 mybatis-config.xml 配置文件也就是解析完毕,可以看到采用了自己写的 ClassLoaderWrapper来操作的, 传递一种 ClassLoader进来,其默认的&系统&线程的,加一起也是有四种. 最后挨个进来迭代,满足条件的会读取文件转化为InputStream,如果都是null的话,也会返回null.

获取SqlSessionFactory & 解析配置文件

new SqlSessionFactoryBuilder() 也是new了一个 SqlSessionFactoryBuild,个人理解 SqlSessionFactoryBuilder 就是专程用来构建出 SqlSessionFactory 来的,毕竟其后面有一个 build 方法.
Problem ? 这里有个问题,为什么不将 SqlSessionFactoryBuilder 的build 方法,修改为静态的 ? 如果修改为静态的话,那就不用new了,就可以直接 SqlSessionFactoryBuilder.build(mybatisInputStream);

SqlSessionFactory

接着我们来到 SqlSessionFactory 的 build 方法.
这里在 finnaly 中, 可以看到 ErrorContext 利用了 ThreadLocal
 

new XmlConfigBuilder() 方法:

到这里,就可以看到 this构造方法以及其之前还有new对象的方法,都已经走完了. 这上面的方法,基本都是再为后面的解析xml文件做准备, 并且还有一些初始化数据的赋值操作.
Note : 注意这里的 BaseBuilder是抽象类,其实现类是有好几个的. 这种写法,其实是将子类的一些common的方法,写入到 BaseBuilder父类中,然后不同的方法,需要子类自己去重写这个方法实现自己的业务逻辑. 当然一些参数也是可以放在抽象类中.
 

build(parser.parse())方法

parser.parse() 方法 :
这里是对 parser.parse() 调用玩返回的 Configuration 传入到新创建的 DefaultSqlSessionFactory 对象中.
也就是说,我们拿到的 SqlSessionFactory 是 DefaultSqlSessionFactory.
 

获取 SqlSession

至此, 可以看到 MyBatis 从SqlSessionFactory中获取出来SqlSession会话, 也可以理解为几个步骤.
首先获取事务工厂, 然后再从事务工厂中获取一个事务来, JdbcTransaction 有兴趣的同学可以看下这个类,里面也是封装了写 commit / rollback等方法. 再接着获取出 执行器(Executor),这里从代码哪里看,执行器还是有几种类型的,也执行自定义. 最后new了一个 DefaultSqlSession 回去.

session.getMapper(BlogMapper.class)

接着看,上一步返回的session,是怎么获取到我们写的Mapper接口文件(Mapper这种文件,在解析配置文件的时候,其实就已经解析到MyBatis的configuration里面去了).
从SqlSession 中获取 BlogMapper我们写的mapper流程, 先从 knownMappers 中根据key获取出来之前加载配置已经加载完毕的信息,如果没用的话,就会抛出没有的异常. 最后使用 Proxy.newProxyIntsance来生成的一个类似接口实现类的代码,不同的是, 在 new MapperProxy 的时候,就已经将接下来需要的信息全部传入进去.
 

blogMapper.selectBlog(1) 方法

竟然 BlogMapper是通过Proxy.newInstance获取出来的,那它是怎么查询的数据库? 又是怎么将字段给映射到 Object一一对应的呢 ?
debug会走到 MapperProxy的invoke方法来
这里可以看到,先是对 INSERT / UPDATE / DELETE / SELECT 进行分类处理, 然后对再分别根据不同的类型进行处理. 都是先有转化为sql,然后将执行结果赋值给result.
至于里面详细的查询执行sql,还有动态sql,每次会话缓存等,后面看到详细的情况再一一说明. 这里只是对MyBatis的基本工作进行了一个梳理. 然后后面再根据基础梳理,再来挨个击碎他们.
至此, MyBatis的入门分析流程是结束的. 理解起来,应该还不是那么难.

🤗 总结归纳

总结文章的内容
根据 com.iyang.mybatis.InitHelloMyBatis , 也就是入门的demo来梳理下流程.
  1. 读取配置文件,也就是将配置文件读取,转化为inptStream流.
  1. 利用 SqlSessionFactoryBuilder 来 解析流, 起内部又利用 BaseBuilder(其又很多实现类,这里用的XMLConfigBuilder)也解析xml配置文件. Configuration configuration 该类中是保存着xml配置文件的很多信息. 然后 DefaultSqlSessionFactory 中有configuration字段,也就是属性.
  1. 然后从 DefaultSqlSessionFactory 中获取 SqlSession来, 并且也会是否开启事务(参考:org.apache.ibatis.transaction.jdbc.JdbcTransaction)类,然后获取 Executor,Executor也是有几种种类的,也可以自己自定义,最后返回一个 DefaultSqlSession 来.
  1. 然后从 SqlSession 中获取我们的接口Mapper, 最后也是利用 Proxy.newProxyInstance 来生成的接口,也就是代理(这里打印出地址池或者debug看地址池,就会很明显的看到是代理对象).
  1. 最后走查询的方法, 也就是走到了 MapperProxy 来. 可以看到MapperProxy里面是有sqlSession的,而SqlSession是有 Executor/configuration/autoCommit等信息的, 有了sqlSession,就剩下执行sql和映射sql查询出来的结果来了(这里是 mapperMethod.execute(sqlSession, args) —> org.apache.ibatis.binding.MapperMethod#execute 走到这里来了,这里之后就会分类进行处理,然后映射sql语句).
  1. 至此,一个 MyBatis 的 HelloWorld分析流程是完毕的.

📎 参考文章

 
💡
有关文章的问题,欢迎您在底部评论区留言,一起交流~