这篇文章我们来深入阅读下Mybatis的源码,希望以后可以对底层框架不那么畏惧,学习框架设计中好的思想;
上面这两幅图来源于网络,不过画的很好,基本说明了Mybatis的架构流程。
说明:
Mybatis配置文件
SqlSessionFactory
SqlSession
Executor执行器
MappedStatement
MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
负责对用户传递的参数转换成JDBC Statement 所需要的参数
负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
负责java数据类型和jdbc数据类型之间的映射和转换
负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回BoundSql表示动态生成的SQL语句以及相应的参数信息
SqlSessionFactoryBuilder#build 构建SqlSessionFactory XMLConfigBuilder#parse 全局配置文件解析,封装成Configuration对象 #parseConfiguration 从根路径开始解析,加载的信息设置到Configuration对象中 #mapperElement 解析mapper映射文件 XMLMapperBuilder#parse 具体解析mapper映射文件 SqlSessionFactoryBuilder#build:创建SqlSessionFactory接口的默认实现类
1.SqlSessionFactoryBuilder创建SqlsessionFactory时,需要传入一个Configuration对象。 2.XMLConfigBuilder对象会去实例化Configuration。 3.XMLConfigBuilder对象会去初始化Configuration对象。 通过XPathParser去解析全局配置文件,形成Document对象 通过XPathParser去获取指定节点的XNode对象。 解析Xnode对象的信息,然后封装到Configuration对象中
|--SqlSessionFactoryBuilder |--XMLConfigBuilder |--XPathParser |--Configuration
XMLConfigBuilder#mapperElement:解析全局配置文件中的<mappers>标签 |--XMLMapperBuilder#构造方法:专门用来解析映射文件的 |--XPathParser#构造方法: |--XPathParser#createDocument():创建Mapper映射文件对应的Document对象 |--MapperBuilderAssistant#构造方法:用于构建MappedStatement对象的 |--XMLMapperBuilder#parse(): |--XMLMapperBuilder#configurationElement:专门用来解析mapper映射文件 |--XMLMapperBuilder#buildStatementFromContext:用来创建MappedStatement对象的 |--XMLMapperBuilder#buildStatementFromContext |--XMLStatementBuilder#构造方法:专门用来解析MappedStatement |--XMLStatementBuilder#parseStatementNode: |--MapperBuilderAssistant#addMappedStatement:创建 MappedStatement对象 |--MappedStatement.Builder#构造方法 |--MappedStatement.Builder#build方法:创建MappedStatement对象,并存储 到Configuration对象中
|--XMLConfigBuilder |--XMLMapperBuilder |--XPathParser |--MapperBuilderAssistant |--XMLStatementBuilder |--MappedStatement
XMLLanguageDriver#createSqlSource 创建SqlSource,解析SQL,封装SQL语句(出参数绑定)和入参信息 XMLScriptBuilder 构造函数:初始化动态SQL中的节点处理器集合 XMLScriptBuilder#parseScriptNode #parseDynamicTags 解析select/insert/ update/delete标签中的SQL语句,最终将解析到的SqlNode封装到MixedSqlNode中的List集合中 DynamicSqlSource 构造方法:如果SQL中包含${}和动态SQL语句,则将SqlNode封装到DynamicSqlSource RawSqlSource 构造方法:如果SQL中包含#{},则将SqlNode封装到RawSqlSource中,并指定parameterType SqlSourceBuilder#parse ParameterMappingTokenHandler 构造方法 GenericTokenParser#构造方法,指定待分析的openToken和closeToken并指定处理器 GenericTokenParser#parse 解析#{} ParameterMappingTokenHandler#handleToken 处理token(#{}/${}) #buildParameterMapping 创建ParameterMapping对象 StaticSqlSource 构造方法,将解析之后的sql信息,封装到StaticSqlSource 对象
|--XMLLanguageDriver |--XMLScriptBuilder |--SqlSource |--SqlSourceBuilder
|--DefaultSqlSession#getMapper:获取Mapper代理对象 |--Configuration#getMapper:获取Mapper代理对象 |--MapperRegistry#getMapper:通过代理对象工厂,获取代理对象 |--MapperProxyFactory#newInstance:调用JDK的动态代理方式,创建Mapper代理
DefaultSqlSession#selectList CachingExecutor#query BaseExecutor#query 委托给BaseExecutor执行 #queryFromDatabase SimpleExecutor#doQuery 执行查询 Configuration#newStatementHandler 创建路由功能的StatementHandler,根据MappedStatement中的StatementType SimpleExecutor#prepareStatement 设置PreapreStatement 的参数 BaseExecutor#getConnection 获取数据库连接 BaseStatementHandler#prepare 创建Statement PrepareStatement、Statement、CallableStatement) PreparedStatementHandler#parameterize 设置参数 PreparedStatementHandler#query 执行SQL语句(已经设置过参数),并且映射结果集 com.mysql.jdbc.PreparedStatement#execute 调用JDBC的api执行Statement DefaultResultSetHandler#handleResultSets 处理结果集
|--DefaultSqlSession |--Executor |--CachingExecutor |--BaseExecutor |--SimpleExecutor |--StatementHandler |--RoutingStatementHandler |--PreparedStatementHandler |--ResultSetHandler |--DefaultResultSetHandler
MappedStatement#getBoundSql DynamicSqlSource#getBoundSql SqlSourceBuilder#parse 执行解析:将带有#{}的SQL语句进行解析,然后封装到StaticSqlSource中 GenericTokenParser #构造方法,指定待分析的openToken和closeToken,并指定处理器 GenericTokenParser#parse 解析SQL语句,处理openToken和closeToken中的内容 ParameterMappingTokenHandler#handleToken 处理token(#{}/${}) #buildParameterMapping 创建 ParameterMapping对象 StaticSqlSource#构造方法 : 将解析之后的SQL信息,封装到StaticSqlSource |--RawSqlSource#getBoundSql |--StaticSqlSource#getBoundSql |--BoundSql#构造方法:将解析后的sql信息、参数映射信息、入参对象组合到BoundSql对象中
|--PreparedStatementHandler#parameterize:设置PreparedStatement的参数 |--DefaultParameterHandler#setParameters:设置参数 |--BaseTypeHandler#setParameter: |--xxxTypeHandler#setNonNullParameter:调用PreparedStatement的setxxx方法
|--DefaultResultSetHandler#handleResultSets |--DefaultResultSetHandler#handleResultSet |--DefaultResultSetHandler#handleRowValues |--DefaultResultSetHandler#handleRowValuesForSimpleResultMap |--DefaultResultSetHandler#getRowValue |--DefaultResultSetHandler#createResultObject:创建映射结果对象 |--DefaultResultSetHandler#applyAutomaticMappings |--DefaultResultSetHandler#applyPropertyMappings
基本上Mybatis的流程就是这样了,其中还有很多实现细节暂时看不太懂。 我认为学习框架源码分为两步:
目前第一步尚有问题,需要多走几遍源码,加深下理解,一起加油~~