mybatis 源码分析(2)主要类代码解析

加载全局配置文件流程

找入口: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
发布了9 篇原创文章 · 获赞 1 · 访问量 178

猜你喜欢

转载自blog.csdn.net/qq_33358408/article/details/103924282
今日推荐