Mybatis Source
测试示例
理解Mybatis
结构上理解
Configuration
存储配置信息
一系列的
boolean变量(safeRowBoundsEnabled,safeResultHandlerEnabled,mapUnderscoreToCamelCase,...),用来控制CURD的input和output存储 环境信息
Environment
存储解析信息
通过 MapperRegistry 缓存了 MapperProxyFactory
存储 InterceptorChain 过滤链
存储 TypeHandlerRegistry
存储 TypeAliasRegistry,
通过 HashMap (
Map<String, MappedStatement> mappedStatements) 存储了MappedStatement一个 MappedStatement 对应 Mapper.xml 中的一个
INSERT,SELECT,DELETE,UPDATE的代码片段
通过 HashMap(
Map<String, Cache>) 存储了 Mybatis 的缓存通过 HashMap(
Map<String, ResultMap>) 存储了 Mapper.xml 中 ResultSet 块通过 HashMap(
Map<String, ParameterMap>) 存储了 Mapper.xml 中 ParameterMap 块通过 HashMap(
Map<String, KeyGenerator>) 存储了KeyGenerator
Environment
包含了 TransactionFactory,用来创建事务
包含了 DataSource,用来获取连接
MapperRegistry
引用了
Configuration一对一映射了 Class 和 MapperProxyFactory
Class: Java代码书写的 Mapper 接口MapperProxyFactory: 生成动态代理抽象的工厂,用来生成MapperProxy
MapperProxy
包含了
SqlSession sqlSession: 一次JDBC执行抽象Session包含了
Class<T> mapperInterface: 对应了 Java编写的Mapper接口包含了
Map<Method, MapperMethod> methodCache: 接口里的每个方法对应了 MapperMethod
创建Mapper接口代理对象的核心是 MapperProxy 实现了 InvocationHandler
MapperMethod
包含了
SqlCommand commandSqlCommand是MappedStatement的引用映射,SqlCommand主要记录了 id 和 typeid 的 作用是从Configuration缓存中找到内容
type是CURD的类型,在真实执行的时候再分发一次
包含了
MethodSignature method,MethodSignature是对接口方法的抽象枚举了返回类型,用boolean表示选择,记录下返回的类类型
引用参数处理器
Mapper接口方法的唯一定义 MapperMethod = Mapper.class + Mapper.method()
MapperMethod在整个Mybatis框架中关联了 Java的接口 和 Xml文件的标签
MappedStatement
对于某个 XXXMapper.xml
其中一定要包含namespace, 指向了Java代码中Mapper的接口
对于
SELCET|INSERT|UPDATE|DELETE,每一块儿解析成MappedStatement
DefaultSqlSessionFactory
引用了
Configuration深层理解 : 引用了
Environment
implements SqlSessionFactory
SqlSessionManager
引用了
Configurationimplements SqlSessionFactory, 通过观察成员变量存在SqlSessionFactory sqlSessionFactory,说明这里是代理implements SqlSession, 表明SqlSessionManager本身就是个SqlSession成员变量声明了
ThreadLocal<SqlSession> localSqlSession, 一般和多线程相关综上从结构上理解,
SqlSessionManager作为Factory可以产生SqlSession, 作为SqlSession可以执行, 因为其又包含了ThreadLocal,所以这个SqlSessionManager暂时理解为是在多个Java方法有SQL调用的时候控制事务使用的
DefaultSqlSession
从SqlSession接口上看, 提供了通用的curd方法, 一般不直接调用。
提供了getMapper()的方法, 这个就是Mybatis提供的ORM
引用了
Configuration, 等价于引用了Environment, 等价于可以获取到DataSource和Transaction定义了执行器:
Executor executor,真实的JDBC调用封装在这个里面
行为上理解
创建 SqlSessionFactory
理解 : SqlSessionFactory 是最终产生 SqlSession 的地方,在创建 SqlSessionFactory 的时候,需要抓住的关键点是在创建过程中基于哪些外部配置文件创建了内部的配置项
这些内部的配置项(Configuration和Environment )是内部逻辑读取外部配置并构建,从SqlSessionFactory的 openSession()方法上可以看出内部的配置是不需要暴露出来的
小结: 这种设计是大部分框架的设计思路,屏蔽不必要的配置细节,通用化配置过程
创建 SqlSessionFactory 的内部有个读取xml文件并解析的工具 XMLConfigBuilder, 这个类继承自 BaseBuilder。 BaseBuilder
声明了
Configuration,TypeAliasRegistry,TypeHandlerRegistry,关键修饰protected,说明子类可以直接使用TypeAliasRegistry和TypeHandlerRegistry是引用的Configuration自身包含的
Mybatis自身规划了很多 Builder (查看 BaseBuilder的继承) 去解析各类配置并存储到 Configuration 中
对于Mapper接口和Mapper.xml文件的解析是在解析Xml文件中的<mapper>标签再次细化
细化出
MapperProxyMapperMethodMapperStatement
Q & A :
Q: Mybatis是屏蔽不必要的配置细节,通用化配置过程的?
A: Mybatis提供一个XML配置文件,通过读取XML配置文件,初始化了相应的Configuration和Environment
获取 SqlSession
与Datasource以及Transaction相关
SqlSession 本身的抽象是对 JDBC 连接以及执行的抽象聚合
引用了
Configuration本质上可以传递了初始化的缓存数据,关键是使用Configuration中的Environment数据从上面的结构可以了解,
Environment主要包含了TransactionFactory和DataSource在构建
SqlSession的时候 构建了Executor包含了Transaction
真正的SQL执行是在Executor中
获取接口代理对象
Proxy.newProxyInstance: JDK的动态代理
对于Mapper而言,无论是接口Mapper还是文件XMLMapper,都被抽象成了MapperProxy
执行细节的抽象就是MapperMethod
执行接口里面的方法 MapperProxy MapperMethod
这里是分发执行就是Mapper接口方法的关键
MapperProxy
观察MapperProxy真实的调用思路
从
Map<Method, MapperMethod> methodCache获取到 Java的Mapper接口映射的MapperMethod方法由
MapperMethod中的Object execute(SqlSession sqlSession, Object[] args)这个方法去执行JDBC逻辑方法的入参
SqlSession sqlSession, 与Sql执行和事务有关方法的入参
Object[] args, 对于接口方法里的参数,Mybatis会将其转换成完整逻辑需要的参数方法的出参 用
Object接收,对应InvocationHandler中invoke的返回对于出参,在JDBC中,返回的结果类型是可枚举的, 所以对每种返回的结果做好映射转换即可
INSERT,UPDATE,DELETE一般返回影响的行数SELECT返回的基于ResultSet可以转换为 单个对象 或者 对象集合如果本身接口方法是
void没有返回值,return null即可
MapperMethod
对外暴露的执行方法 Object execute(SqlSession sqlSession, Object[] args)
方法执行逻辑
枚举
SqlCommand的类型(INSERT|UPDATE|DELETE|SELECT|FLUSH), 分发执行类型SELECT的执行又细化了returnManyreturnMapreturnsCursorreturnOne
对于影响行数的返回单独处理, (
int|Integer|long|Long|boolean|Boolean) boolean是业务封装对于接口方法为
void的处理是最简单的,return null即可、真实的执行还是由
SqlSession来执行的,SqlSession在框架中是距离JDBC最近的抽象封装SqlSession执行的本质是Executor<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds)
Executor
真正执行JDBC操作的入口
理解Java对于JDBC事务的封装
Transaction的设计