(一)解析mybatis-config.xml


SqlSessionFactoryBuilder调用build方法:

在方法内部创建了一个XMLConfigBuilder对象,在父类构造器实例化了Configuration对象.XMLConfigBuilder对象是专门用来解析mybatis-config.xml文件的,然后开始解析mybatis-config.xml配置文件里面的所有标签,比如数据源,事务工厂,别名,插件等等.解析的结果放入到Configuration对象.

(二)解析Mapper.xml并且返回SqlSessionFactory


然后XMLConfigBuilder会创建XMLMapperBuilder专门用来解析Mapper.xml的.然后开始解析Mapper.xml里面的内容, 又创建一个XMLStatementBuilder对象专门用来解析Mapper.xml里面的insert update delete select 标签,然后给增删改查标签的所有属性,比如resultMap paramterMap等等属性全部解析完了以后封装到MappedStatement对象. 一个增删改查标签对应一个MappedStatement对象 . 这个就类似于解析一个Bean标签放到BeanDefinition对象里面一样.
MappedStatement对象最终也会放入到Configuration对象里面去.
一个MappedStatement对应Mapper.xml里面的一个增删改查标签.

然后调用org.apache.ibatis.builder.xml.XMLMapperBuilder#bindMapperForNamespace 把Mapper接口和Mapper映射器的文件绑定起来,同时调用
org.apache.ibatis.binding.MapperRegistry#addMapper把接口类型作为key,value是这个接口类型的MapperProxyFactory放入到了knownMappers(HashMap)容器里面.

最终将解析的结果放到Configuration对象里面去.

最后实例化DefaultSqlSessionFactory并且在构造方法里面给Configuration进行构造注入,最后 返回sqlSessionFactory对象.

Mybatis启动流程 - 图1

(三)产生SqlSession对象


然后sqlSessionFactory调用openSession时候会通过解析内部的Configuration对象的数据库连接信息,然后通过数据源对象实例化事务工厂,然后从事务工厂获取事务,然后创建Executor执行器(基于事物对象和传入的Executor类型创建的,如果用户没指定就创建默认的Executor执行器对象,如果用户指定了特定的Executor执行器,就创建这个特定的Executor执行器对象),然后判断用户是否开启了二级缓存,如果开启了二级缓存的话,会实例化CachingExecutor对刚刚创建的Executor执行器进行装饰(装饰者设计模式),
然后调用org.apache.ibatis.plugin.InterceptorChain#pluginAll循环遍历所有的插件,然后这些插件一次又对Executor执行器进行包装,最后返回了执行器.

最后返回DefaultSqlSession对象, 这个DefaultSqlSession对象包含了Configuration对象和Executor执行器和autoCommit(boolean类型的)参数.


Mybatis启动流程 - 图2




然后通过SqlSession对象调用getMapper从Configuration 对象获取MapperProxyFactory对象,然后从MapperProxyFactory对象开始生成代理对象并且返回.

再然后获取到代理对象之后,调用方法,会先执行到MapperProxy的invoke方法,在invoke方法内部会先获取MapperMethod对象,然后通过MapperMethod对象调用execute执行SQL语句,执行的时候会先判断你是select 还是insert还是update还是delete语句,每种语句调用不同的jdbc方法.
然后调用Executor的query方法, 在query方法内部会实例化BoundSql类,BoundSql包装了sql信息和参数和返回值类型等等.

在执行完了sql语句之后会将结果加入到一级缓存里面,最后将查询结果返回到最上层.


在一个线程内重复执行一个方法, 第二次会走一级缓存.而不会走数据库, 缓存的key是 全限定类名加接口方法名加SQL语句拼接成的字符串.


(四)调用getMapper返回接口对象

搞了个Mapper对象是为了解决JDBC的SQL写在代码里面的强耦合.

SqlSession对象调用getMapper之后,内部会从Configuration对象调用getMapper,然后又从mapperRegistry对象调用getMapper方法,然后从knownMappers容器里面根据传入的接口类型,获取到对应的MapperProxyFactory类.然后通过MapperProxyFactory获取到MapperProxy对象,然后通过MapperProxy对象实例化Mapper对象(通过jdk动态代理的方式,参数是类加载器被代理类和mapperProxy代理类).


(五)Mapper对象执行对应的方法


Mapper接口代理类对象是通过动态代理的方式产生的,只要执行mapper接口代理类对象的任意增删改查方法,会先执行到MapperProxy的invoke方法.
执行前先判断是不是Object本身的方法,如果是的话直接去执行(因为Object不是操作数据库的方法),

然后获取到Method方法对象,通过Method对象获取到对应的MapperMethod对象

然后通过MapperMethod调用execute方法根据我们从操作类型(这个操作类型是对数据库的增删改查四个操作类型的一个),进行对应的查询还是删除操作等等.
比如说查询语句会通过Configuration对象根据statement(是mapper接口的类的类型加方法名的字符串,比如说com.dao.userDao.selectById )获取到对应的MapperStatement对象(MapperStatement里面有执行的目标方法的sql语句),
然后Executor对象执行query操作(参数是MapperStatement对象,BoundSql ),如果开启二级缓存的话,会先走CachingExecutor这个装饰类再走到BaseExecutor类.然后开始执行Executor的query方法.

先从缓存里面尝试获取之前查到的相同的SQL语句参数的结果,如果获取不到的话调用org.apache.ibatis.executor.BaseExecutor#queryFromDatabase去数据库查询

queryFromDatabase调用doQuery 从MappedStatement里面获取到Configuration对象 ,然后实例化StatementHandler对象(StatementHandler是对Statement的封装),默认创建的是PreparedStatementHandler对象.然后调用PreparedStatementHandler的父类BaseStatementHandler进行属性的初始化赋值,然后重点是创建了parameterHandler和ResultSetHandler两个对象.
parameterHandler是给方法参数转换成jdbc的参数,ResultSetHandler是给我们的结果集转换成我们的返回值对象的参数.


然后开始调用org.apache.ibatis.executor.SimpleExecutor#prepareStatement对SQL语句开始预编译了 ,方法内部是StatementHandler调用prepare对参数啥的进行处理/

然后StatementHandler调用query方法进行查询操作了,方法内部statement调用execute()方法(这是jdbc的方法)进行查询的操作.查询完了会给结果集放入到statement里面.

最后resultSetHandler调用handlerResultSets对查询出来的结果集转换成返回Java对象.

查询完了给结果放入缓存里面



MapperMethod

里面有SqlCommand对象(包括了增删改查的操作类型和SQL相关的信息等等)
MethodSignature 方法签名

MapperProxy


mapper.java里面的接口的方法和Mapper.xml的增删改查标签的id是一一对应的,我们就可以通过mapper.Java接口方法名找到Mapper.xml里面对应的增删改查的那个标签.