1、mybatis 整体功能架构
mybatis 主要分为三层,从上到下依次为:接口层、数据处理层、基础支撑层,架构图如下所示:
2、mybatis 四大核心JDBC组件简介
mybatis 内置核心4大功能组件,分别是Executor、StatementHandler、ParameterHandler、ResultSetHandler,功能说明 如下:
组件名称 | 组件说明 |
---|---|
Executor | 框架核心调度执行器组件,主要用来调用生成sql语句和缓存维护,主要有两个实现:BaseExecutor、CachingExecutor |
StatementHandler | 用来封装jdbc statement的相关操作,设置参数、结果映射等,主要实现有BaseStatementHandler、CallableStatementHandler、PreparedStatementHandler、SimpleStatementHanlder、RoutingStatementHandler。 |
ParameterHandler | 主要用来处理传入参数到statement所需参数的映射 |
ResultSetHandler | 主要用来将jdbc返回结果映射到具体的List集合,完成从数据库类型到程序实体类的转化,默认实现为DefaultResultSethandler |
3、mybatis mapper代理工作流程示意图
4、mybatis 核心类说明
类名 | 类描述 |
---|---|
SqlSessionFactoryBuilder | SqlSessionFactory构造器,构建者模式,使用build方法,可根据输入流InputStream、Reader等进行构建 |
SqlSessionFactory | SqlSession工厂类,用于创建SqlSession, 传入参数Configuration |
SqlSession | SqlSession代码一次sql执行会话,里面携带着全局配置信息 |
Configuration | mybatis 全局配置管理对象,包含mybatis所有的配置信息,包括数据源和所有的xml文件信息 |
MappedStatement | 和一个insert|update|delete|select 标签对应的对象,用来存储一个sql语句片段信息 |
SqlSource | 用来针对不同类型的sql语句生成最终的可执行的sql语句,主要实现有DynamicSqlSource、RawSqlSource、StaticSqlSource、MixedSqlSource |
BoundSql | 用来将sql语句片段和参数进行绑定存储,携带着sql语句和参数信息 |
TypeHandler | 用来完成java类型和jdbc数据类型的转换 |
XMLConfigBuilder | 主要用来解析全局配置信息,如:environment, dataSource等信息,并封装到Configuration中 |
XMLMapperBuilder | 主要用来解析xml文件中的select|insert|update|delete标签,并封装成MappedStatement存储到Configuration中 |
XMLScriptBuilder | 主要用来解析将sql语句中的各个动态标签及动态sql语句,解析和参数映射后,最终构造成StaticSqlSource输出保存可执行的完整sql语句 |
XPathParser | 主要用来解析配置文件,形成可基于dom操作的Document文档对象 |
ParameterMapping | 用来保存sql中动态参数名称和参数值的映射关系的对象 |
5、mybatis 配置初始化部分核心源码
5.1、程序代码入口分析: SqlSessionFactoryBuilder#build
SqlSessionFactoryBuilder: 用来初始化SqlSessionFactory, 默认使用DefaultSqlSessionFactory实现
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// XMLConfigBuilder:用来解析XML配置文件
// 使用构建者模式
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// parser.parse():使用XPATH解析XML配置文件,将配置文件封装为Configuration对象
// 返回DefaultSqlSessionFactory对象,该对象拥有Configuration对象(封装配置文件信息)
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
// 创建SqlSessionFactory接口的默认实现类
return new DefaultSqlSessionFactory(config);
}
复制代码
5.2、解析全局配置信息Configuration:XMLConfigBuilder#parse
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
/**
* 解析XML配置文件
* @return
*/
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// parser.evalNode("/configuration"):通过XPATH解析器,解析configuration根节点
// 从configuration根节点开始解析,最终将解析出的内容封装到Configuration对象中
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
// 解析</properties>标签
propertiesElement(root.evalNode("properties"));
// 解析</settings>标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
// 解析</typeAliases>标签
typeAliasesElement(root.evalNode("typeAliases"));
....
....
....
// 解析</environments>标签
environmentsElement(root.evalNode("environments"));
// 解析</databaseIdProvider>标签
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 解析</typeHandlers>标签
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析</mappers>标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
复制代码
6、mybatis mapper文件加载部分核心源码
6.1 解析mapper文件**: **XMLConfigBuilder#mapperElement->XMLMapperBuilder#parse
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
// 通过XMLMapperBuilder解析mapper映射文件
mapperParser.parse();
public void parse() {
// mapper映射文件是否已经加载过
if (!configuration.isResourceLoaded(resource)) {
// 从映射文件中的<mapper>根标签开始解析,直到完整的解析完毕
configurationElement(parser.evalNode("/mapper"));
// 标记已经解析
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
/**
* 解析映射文件
* @param context 映射文件根节点<mapper>对应的XNode
*/
private void configurationElement(XNode context) {
try {
// 获取<mapper>标签的namespace值,也就是命名空间
String namespace = context.getStringAttribute("namespace");
....
....
....
// 解析<parameterMap>子标签
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// 解析<resultMap>子标签
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 解析<sql>子标签,也就是SQL片段
sqlElement(context.evalNodes("/mapper/sql"));
// 解析<select>\<insert>\<update>\<delete>子标签
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
复制代码
6.2 解析MappedStatement: XMLMapperBuilder#buildStatementFromContext
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// MappedStatement解析器
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// 解析select等4个标签,创建MappedStatement对象
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
MapperBuilderAssistant#addMappedStatement
//利用构建者模式,去创建MappedStatement.Builder,用于创建MappedStatement对象
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
// 通过MappedStatement.Builder,构建一个MappedStatement
MappedStatement statement = statementBuilder.build();
// 将MappedStatement对象存储到Configuration中的Map集合中,key为statement的id,value为MappedStatement对象
configuration.addMappedStatement(statement);
复制代码
6.3 处理SqlSource: XMLStatementBuilder#parseStatementNode->langDriver.createSqlSource
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
// 创建SqlSource,解析SQL,封装SQL语句(未参数绑定)和入参信息
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
XMLLanguageDriver#createSqlSource
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
// 初始化了动态SQL标签处理器
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
// 解析动态SQL
return builder.parseScriptNode();
}
public SqlSource parseScriptNode() {
// 解析select\insert\ update\delete标签中的SQL语句,最终将解析到的SqlNode封装到MixedSqlNode中的List集合中
// ****将带有${}号的SQL信息封装到TextSqlNode
// ****将带有#{}号的SQL信息封装到StaticTextSqlNode
// ****将动态SQL标签中的SQL信息分别封装到不同的SqlNode中
MixedSqlNode rootSqlNode = parseDynamicTags(context);
SqlSource sqlSource = null;
// 如果SQL中包含${}和动态SQL语句,则将SqlNode封装到DynamicSqlSource
if (isDynamic) {
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
// 如果SQL中包含#{},则将SqlNode封装到RawSqlSource中,并指定parameterType
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
return sqlSource;
}
需要相关Java资料的可以通过扫一扫领取