mybatis底层源码
一、运行原理

二、配置文件的解析以及创建SqlSessionFactory 
首先通过配置文件的文件流创建SqlSessionFactoryBuilder对象

调用build方法,传入文件流

之后通过解析器解析xml配置文件

通过XPathParse解析configuration节点,获取根节点,之后再parseConfiguration()方法中根据根节点解析根节点中的每一个节点


之后来到settingsElement()方法中

environmentsElement(root.evalNode("environments"))获取数据源配置被放到了Configuration里面

解析mappers.xml配置文件

两种方式
我们看看配置文件里面mappers标签是怎么配置的,官方给出了四种配置方式:
1、Mapper.xml文件的相对路径引用(解析XML获取SQL)
2、Mapper.xml文件的绝对路径引用(解析XML获取SQL)
3、Mapper.java类文件的完全限定类名(解析注解获取SQL)
4、Mapper.java类文件所在的包路径(解析注解获取SQL)

既然配置有4种配置方法,那对应的解析的时候也有4种解析方法:
XMLConfigBuilder.mapperElement

XMLMapperBuilder.parse()获取mapper配置节点

解析mapper文件中的节点

之后调用XbuildStatementFromContext()方法,对所有的crud配置节点,进行解析

循环解析所有crud节点

解析并获取所有crud节点的属性

最后将所有的属性值加入到一个MappedStatement中,封装成MappedStatement,所以每一个MappedStatement表示一个crud的SQL语句详细信息

然后将每一个MappedStatement添加到MappedStatements集合中,最后加入configuration,到此,configuration就填充完毕,其中保存了所有的配置信息(全局配置文件及sql映射文件)

通过configuration创建DefaultSqlSessionFactory

总结:就是将所有的配置文件信息保存在configuration中,通过configuration对象创建SqlSessionFactory
三、SqlSession对象的创建
通过SqlSessionFactory的openSession获取sqlSession

首先通过configuration.getDefaultExecutorType()获取执行器类型,默认为SIMPLE

之后又来到openSessionFromDataSource()方法

创建了一个Executor对象,来到newExecutor()方法

Executor是一个接口,用来执行crud的

是否配置了二级缓存,如果配置了使用CachingExecutor对Executor包装,实际执行crud还是Executor

包装后的Executor在查询之前会有缓存操作,Executor创建完毕后

会调用连接器链对executor进行一个拼装

循环所有的拦截器重新包装Executor,并返回

将创建好的Executor对象传入DefaultSqlSession中,DefaultSqlSession是SQLSession的实现类,
可以看出DefaultSqlSession中也包含了全局配置文件configuration的数据,最终执行crud还是Executor
总结:创建Executor对象及DefaultSqlSession对象,注意如果有二级缓存会包装Executor,其中还会使用拦截器链包装Executor
四、获取Mapper的代理对象
通过getMapper获取mapper

最终调用configuration的getMapper方法

又调用mapperRegistry的getMapper方法

mapperRegistry中保存了每一个mapper对应的MapperProxyFactory

根据接口类型获取mapperProxyFactory,通过mapperProxyFactory创建代理对象

首先创建一个mapperProxy对象,在调用newInstance方法

MapperProxy实现InvocationHandler接口,这个是JDK做动态代理需要传入的对象

之后就是通过JDK代理创建代理对象并返回,代理对象中包含了sqlSession,可以用来执行crud
总结:mapperProxyFactory在configuration初始化完毕后,一个mapper就绑定一个mapperProxyFactory,
通过mapperProxyFactory创建mapperProxy代理对象,代理对象中保存sqlSession对象,sqlSession中包含类Executor对象,用来执行crud
五、代理对象执行增删改查
调用代理的目标方法时,会先执行invoke()方法

先判断执行的方法是否是Object中的方法,否则就将方法包装为一个MapperMethod,最后执行其execute方法,传入sqlSession及方法参数

判断sql语句的类型,我这里是查询

我这里返回对象进入else流程,convertArgsToSqlCommandParam在解析参数,单个参数直接返回,多个参数返回一个map,之后调用SqlSession的selectOne方法

调用selectList查询多个方法

从configuration中通过方法id获取MappedStatement(就是configuration初始化时用来执行crud的),之后调用executor的query方法,
wrapCollection(parameter)是根据参数将其包装为一个map,map中存放数据

现获取绑定的sql

BoundSql中封装了所有的sql信息,包括sql语句,参数,参数映射关系,之后就是创建二级缓存中保存的key,之后就调用query方法

如果配置二级缓存先获取缓存,之后调用query方法,就是SimpleExecutor的query方法

先从一级缓存中查询获取,这就印证了mybatis先查询二级缓存,在查询一级缓存,如果一级缓存中也没有就执行queryFromDatabase方法

调用doQuery()查询数据,查询出数据后又加入到本地缓存中

首先声明一个Statement对象,原生JDBC对象,在获取configuration,在通过newStatementHandler创建StatementHandler对象,StatementHandler可以创建出Statement对象

首先创建一个 RoutingStatementHandler

根据配置创建不同的Statement,默认PREPARED,所以创建出一个PreparedStatementHandler,保存在RoutingStatementHandler中,
之后又将statementHandler包装在拦截器链中,之后调用prepareStatement(handler, ms.getStatementLog())方法创建Statement

在prepareStatement中有对参数进行预编译

调用parameterHandler进行参数预编译设置参数,创建PreparedStatementHandler对象时创建parameterHandler及resultSetHandler,在创建这两个对象时,
又将其包装到拦截器链中,至此mybatis的四大对象(Executor,StatementHandler,parameterHandler,resultSetHandler)就全部创建完毕,调用setParameters设置参数

调用TypeHandler给sql语句预编译设置参数,参数设置完毕就调用handler.

通过resultSetHandler处理结果

最后通过typeHandler.getResult(rs, column)返回结果
总结:先通过代理mapper对象,实际执行crud是使用sqlSession,sqlSession又是使用executor执行的,executor在执行crud时,
会创建StatementHandler,StatementHandler就是用来处理(预编译,设置参数等)sql语句,
StatementHandler创建时创建了parameterHandler及resultSetHandler,
parameterHandler设置参数等等工作,并且执行sql语句,
resultSetHandler是用来处理查询后的结果,
parameterHandler及resultSetHandler执行时都会有一个TypeHandler做设置参数及获取结果映射为javaBean,TypeHandler底层是使用JDBC操作的
六、运行流程总结
- 
根据配置文件(全局文件及sql映射文件)初始化出Configuration 
- 
创建DefaultSqlSession对象,其中包括Configuration及Executor(根据全局配置文件中的defaultExecutorType进行初始化) 
- 
DefaultSqlSession或Mapper接口对应的MapperProxy,MapperProxy包含DefaultSqlSession 
- 
执行增删改查方法,代理对象调用DefaultSqlSession(Executor)的CRUD,创建一个Statement对象,同时创建StatementHandler,创建StatementHandler同时也会创建出parameterHandler及resultSetHandler,调用StatementHandler(parameterHandler)的预编译参数及设置参数值,在调用StatementHandler的CRUD方法,使用resultSetHandler封装结果 
- 
四大对象每个创建时都有一个拦截器链的步骤,这一步在mybatis的插件中有用。 
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号