加载全局配置文件流程
找入口:SqlSessionFactoryBuilder#build方法
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.
}
}
}
流程分析
SqlSessionFactoryBuilder#build :用于构建SqlSessionFactory对象
|--XMLConfigBuilder#构造参数:用来解析全局文件文件的解析器
|--XPathParser#构造参数:用来使用XPath语法解析XML的解析器
|--XPathParser#createDocument():解析全局配置文件,封装为Document对
象(封装一些子节点,使用XPath语法解析获取)
|--Configuration#构造参数:创建Configuration对象,同时初始化内置类的别名
|--XMLConfigBuilder#parse():全局配置文件的解析器
|--XPathParser#evalNode(xpath语法):XPath解析器,专门用来通过Xpath语法解析
XML返回XNode节点
|--XMLConfigBuilder#parseConfiguration(XNode):从全局配置文件根节点开始解
析,加载的信息设置到Configuration对象中
|--SqlSessionFactoryBuilder#build:创建SqlSessionFactory接口的默认实现类
DefaultSqlSessionFactory(Configuration对象)
总结:
1.SqlSessionFactoryBuilder创建SqlsessionFactory时,需要传入一个Configuration
对象。
2.XMLConfigBuilder对象会去实例化Configuration。
3.XMLConfigBuilder对象会去初始化Configuration对象。
通过XPathParser去解析全局配置文件,形成Document对象
通过XPathParser去获取指定节点的XNode对象。
解析Xnode对象的信息,然后封装到Configuration对象中
相关类和接口:
|--SqlSessionFactoryBuilder
|--XMLConfigBuilder
|--XPathParser
|--Configuration
加载映射文件流程
找入口:XMLConfigBuilder#mapperElement方法
/**
* 解析<mappers>标签
* @param parent mappers标签对应的XNode对象
* @throws Exception
*/
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
// 获取<mappers>标签的子标签
for (XNode child : parent.getChildren()) {
// <package>子标签
if ("package".equals(child.getName())) {
// 获取mapper接口和mapper映射文件对应的package包名
String mapperPackage = child.getStringAttribute("name");
// 将包下所有的mapper接口以及它的代理对象存储到一个Map集合中,key为mapper接口类型,value为代理对象工厂
configuration.addMappers(mapperPackage);
} else {// <mapper>子标签
// 获取<mapper>子标签的resource属性
String resource = child.getStringAttribute("resource");
// 获取<mapper>子标签的url属性
String url = child.getStringAttribute("url");
// 获取<mapper>子标签的class属性
String mapperClass = child.getStringAttribute("class");
// 按照 resource ---> url ---> class的优先级去解析取<mapper>子标签,它们是互斥的
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream =
Resources.getResourceAsStream(resource);
// 专门用来解析mapper映射文件
XMLMapperBuilder mapperParser = new
XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
// 通过XMLMapperBuilder解析mapper映射文件
mapperParser.parse();
} else if (resource == null && url != null && mapperClass ==
null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new
XMLMapperBuilder(inputStream, configuration, url,
configuration.getSqlFragments());
// 通过XMLMapperBuilder解析mapper映射文件
mapperParser.parse();
} else if (resource == null && url == null && mapperClass !=
null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
// 将指定mapper接口以及它的代理对象存储到一个Map集合中,key为mapper接口类型,value为代理对象工厂
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a
url, resource or class, but not more than one.");
}
}
}
}
}
流程分析
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#build方法:创建MappedStatement
对象,并存储到Configuration对象中
相关类和接口:
|--XMLConfigBuilder
|--XMLMapperBuilder
|--XPathParser
|--MapperBuilderAssistant
|--XMLStatementBuilder
|--MappedStatement
SqlSource创建流程
找入口:XMLLanguageDriver#createSqlSource
@Override
public SqlSource createSqlSource(Configuration configuration, XNode
script, Class<?> parameterType) {
// 初始化了动态SQL标签处理器
XMLScriptBuilder builder = new XMLScriptBuilder(configuration,
script, parameterType);
// 解析动态SQL
return builder.parseScriptNode();
}
SqlSource创建流程分析
|--XMLLanguageDriver#createSqlSource:创建SqlSource
|--XMLScriptBuilder#构造方法:初始化动态SQL中的节点处理器集合
|--XMLScriptBuilder#parseScriptNode:
|--XMLScriptBuilder#parseDynamicTags:解析select\insert\
update\delete标签中的SQL语句,最终将解析到的SqlNode封装到MixedSqlNode中的List集合中
|--DynamicSqlSource#构造方法:如果SQL中包含${}和动态SQL语句,则将SqlNode封
装到DynamicSqlSource
|--RawSqlSource#构造方法:如果SQL中包含#{},则将SqlNode封装到RawSqlSource
中
|--ParameterMappingTokenHandler#构造方法
|--GenericTokenParser#构造方法:指定待分析的openToken和closeToken,
并指定处理器
|--GenericTokenParser#parse:解析SQL语句,处理openToken和
closeToken中的内容
|--ParameterMappingTokenHandler#handleToken:处理token(#
{}/${})
|--ParameterMappingTokenHandler#buildParameterMapping:
创建ParameterMapping对象
|--StaticSqlSource#构造方法:将解析之后的SQL信息,封装到
StaticSqlSource
相关类和接口:
|--XMLLanguageDriver
|--XMLScriptBuilder
|--SqlSource
|--SqlSourceBuilder
获取Mapper代理对象流程
找入口:DefaultSqlSession#getMapper
@Override
public <T> T getMapper(Class<T> type) {
// 从Configuration对象中,根据Mapper接口,获取Mapper代理对象
return configuration.<T>getMapper(type, this);
}
流程分析
|--DefaultSqlSession#getMapper:获取Mapper代理对象
|--Configuration#getMapper:获取Mapper代理对象
|--MapperRegistry#getMapper:通过代理对象工厂,获取代理对象
|--MapperProxyFactory#newInstance:调用JDK的动态代理方式,创建Mapper
代理
SqlSession执行主流程
找入口:DefaultSqlSession#selectList()
public <E> List<E> selectList(String statement, Object parameter, RowBounds
rowBounds) {
try {
// 根据传入的statementId,获取MappedStatement对象
MappedStatement ms =
configuration.getMappedStatement(statement);
// 调用执行器的查询方法
// RowBounds是用来逻辑分页
// wrapCollection(parameter)是用来装饰集合或者数组参数
return executor.query(ms, wrapCollection(parameter), rowBounds,
Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database.
Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
流程分析
|--DefaultSqlSession#selectLIst
|--CachingExecutor#query
|--BaseExecutor#query
|--BaseExecutor#queryFromDatabase
|--SimpleExecutor#doQuery
|--Configuration#newStatementHandler:创建
StatementHandler,用来执行MappedStatement对象
|--RoutingStatementHandler#构造方法:根据路由规则,设置
不同的StatementHandler
|--SimpleExecutor#prepareStatement:主要是设置
PreparedStatement的参数
|--SimpleExecutor#getConnection:获取数据库连接
|--PreparedStatementHandler#prepare:创建
PreparedStatement对象
|--PreparedStatementHandler#parameterize:设置
PreparedStatement的参数
|--PreparedStatementHandler#query:主要是用来执行SQL语句,
及处理结果集
|--PreparedStatement#execute:调用JDBC的api执行
Statement
|--DefaultResultSetHandler#handleResultSets:处理
结果集
相关类和接口:
|--DefaultSqlSession
|--Executor
|--CachingExecutor
|--BaseExecutor
|--SimpleExecutor
|--StatementHandler
|--RoutingStatementHandler
|--PreparedStatementHandler
|--ResultSetHandler
|--DefaultResultSetHandler
BoundSql获取流程
找入口:MappedStatement#getBoundSql方法
public BoundSql getBoundSql(Object parameterObject) {
// 调用SqlSource获取BoundSql
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings =
boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(),
parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
流程分析
|--DynamicSqlSource#getBoundSql
|--SqlSourceBuilder#parse:解析SQL语句中的#{},并将对应的参数信息封装到
ParameterMapping对象集合中,然后封装到StaticSqlSource中
|--ParameterMappingTokenHandler#构造方法
|--GenericTokenParser#构造方法:指定待分析的openToken和closeToken,并指定
处理器
|--GenericTokenParser#parse:解析SQL语句,处理openToken和closeToken中的
内容
|--ParameterMappingTokenHandler#handleToken:处理token(#{}/${})
|--ParameterMappingTokenHandler#buildParameterMapping:创建
ParameterMapping对象
|--StaticSqlSource#构造方法:将解析之后的SQL信息,封装到StaticSqlSource
|--RawSqlSource#getBoundSql
|--StaticSqlSource#getBoundSql
|--BoundSql#构造方法:将解析后的sql信息、参数映射信息、入参对象组合到
BoundSql对象中
参数映射流程
找入口:PreparedStatementHandler#parameterize方法
public void parameterize(Statement statement) throws SQLException {
// 通过ParameterHandler处理参数
parameterHandler.setParameters((PreparedStatement) statement);
}
流程分析
|--PreparedStatementHandler#parameterize:设置PreparedStatement的参数
|--DefaultParameterHandler#setParameters:设置参数
|--BaseTypeHandler#setParameter:
|--xxxTypeHandler#setNonNullParameter:调用PreparedStatement的
setxxx方法
结果集映射流程
找入口:DefaultResultSetHandler#handleResultSets方法
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling
results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 获取第一个结果集,并放到ResultSet装饰类
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理结果集
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping =
nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId =
parentMapping.getNestedResultMapId();
ResultMap resultMap =
configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
流程分析
|--DefaultResultSetHandler#handleResultSets
|--DefaultResultSetHandler#handleResultSet
|--DefaultResultSetHandler#handleRowValues
|--DefaultResultSetHandler#handleRowValuesForSimpleResultMap
|--DefaultResultSetHandler#getRowValue
|--DefaultResultSetHandler#createResultObject:创建映射结果
对象
|--DefaultResultSetHandler#applyAutomaticMappings
|--DefaultResultSetHandler#applyPropertyMappings
相关类和接口:
|--DefaultResultSetHandler