MyBatis(8)——运行原理-初始化SqlSessionFactory

总体流程图如下:

测试用例:

@Test
public void testInterface() throws IOException {
	String resource = "mybatis-config.xml";
	InputStream inputStream = Resources.getResourceAsStream(resource);
	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	SqlSession session = sqlSessionFactory.openSession();
	try {
		EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
		Employee employee = mapper.selectEmployee(121);
		System.out.println(employee);
	} finally {
		session.close();
	}
}

 

1、断点调试开始:

首先调用SqlSessionFactoryBuilder的build方法:

2、调用public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)方法:

3、调用XMLConfigBuilder的public Configuration parse()方法:

4、调用parseConfiguration()方法

parseConfiguration(XNode root)方法中,解析全局配置文件中的properties、settings、typeAliases、plugins、objectFactory、objectWrapperFactory、reflectorFactory、environments、databaseIdProvider、typeHandlers、mappers标签。

5、调用settingsElement(settings);方法,设置settings的配置信息到configuration对象中。

private void settingsElement(Properties props) throws Exception {
    configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
    configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
    configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
    configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
    configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
    configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
    configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
    configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
    configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
    configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
    configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
    configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
    configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
    configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
    configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
    configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
    configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
    configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
    configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
    @SuppressWarnings("unchecked")
    Class<? extends TypeHandler> typeHandler = (Class<? extends TypeHandler>)resolveClass(props.getProperty("defaultEnumTypeHandler"));
    configuration.setDefaultEnumTypeHandler(typeHandler);
    configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
    configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
    configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
    configuration.setLogPrefix(props.getProperty("logPrefix"));
    @SuppressWarnings("unchecked")
    Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
    configuration.setLogImpl(logImpl);
    configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
  }

6、调用mapperElement(root.evalNode("mappers"));方法,解析mappers标签:

private void mapperElement(XNode parent) throws Exception {
	if (parent != null) {
		for (XNode child : parent.getChildren()) {
			if ("package".equals(child.getName())) {
				String mapperPackage = child.getStringAttribute("name");
				configuration.addMappers(mapperPackage);
			} else {
				String resource = child.getStringAttribute("resource");
				String url = child.getStringAttribute("url");
				String mapperClass = child.getStringAttribute("class");
				if (resource != null && url == null && mapperClass == null) {
					ErrorContext.instance().resource(resource);
					InputStream inputStream = Resources.getResourceAsStream(resource);
					XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource,
							configuration.getSqlFragments());
					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());
					mapperParser.parse();
				} else if (resource == null && url == null && mapperClass != null) {
					Class<?> mapperInterface = Resources.classForName(mapperClass);
					configuration.addMapper(mapperInterface);
				} else {
					throw new BuilderException(
							"A mapper element may only specify a url, resource or class, but not more than one.");
				}
			}
		}
	}
}

mapper文件根据resource属性指定路径所以只执行下方代码:

mapperParser对象:

7、调用mapperParser.parse();方法:

调用XMLMapperBuilder对象的parse()方法:

调用configurationElement(XNode context)方法:解析mapper文件中的各个标签,如namespace、cache、parameterMap等,最终解析select|insert|update|delete四个基本标签。

8、调用buildStatementFromContext(context.evalNodes("select|insert|update|delete"));方法,即调用buildStatementFromContext(List<XNode> list)方法:

因为没有在全局配置文件中配置databaseId,因此调用buildStatementFromContext(list, null);方法:

遍历每个select|insert|update|delete标签,单独解析每个标签。

XMLStatementBuilder对象statementParser的结构如下:

9、调用XMLStatementBuilder对象的statementParser.parseStatementNode();方法:解析标签中的各个属性值,

public void parseStatementNode() {
	String id = context.getStringAttribute("id");
	String databaseId = context.getStringAttribute("databaseId");

	if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
		return;
	}

	Integer fetchSize = context.getIntAttribute("fetchSize");
	Integer timeout = context.getIntAttribute("timeout");
	String parameterMap = context.getStringAttribute("parameterMap");
	String parameterType = context.getStringAttribute("parameterType");
	Class<?> parameterTypeClass = resolveClass(parameterType);
	String resultMap = context.getStringAttribute("resultMap");
	String resultType = context.getStringAttribute("resultType");
	String lang = context.getStringAttribute("lang");
	LanguageDriver langDriver = getLanguageDriver(lang);

	Class<?> resultTypeClass = resolveClass(resultType);
	String resultSetType = context.getStringAttribute("resultSetType");
	StatementType statementType = StatementType
			.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
	ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);

	String nodeName = context.getNode().getNodeName();
	SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
	boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
	boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
	boolean useCache = context.getBooleanAttribute("useCache", isSelect);
	boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

	// Include Fragments before parsing
	XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
	includeParser.applyIncludes(context.getNode());

	// Parse selectKey after includes and remove them.
	processSelectKeyNodes(id, parameterTypeClass, langDriver);

	// Parse the SQL (pre: <selectKey> and <include> were parsed and
	// removed)
	SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
	String resultSets = context.getStringAttribute("resultSets");
	String keyProperty = context.getStringAttribute("keyProperty");
	String keyColumn = context.getStringAttribute("keyColumn");
	KeyGenerator keyGenerator;
	String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
	keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
	if (configuration.hasKeyGenerator(keyStatementId)) {
		keyGenerator = configuration.getKeyGenerator(keyStatementId);
	} else {
		keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
				configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
						? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
	}

	builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout,
			parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache,
			resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}

10、调用public MappedStatement addMappedStatement()方法:封装标签的属性信息成一个MappedStatement对象:statement

public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType,
		SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap,
		Class<?> parameterType, String resultMap, Class<?> resultType, ResultSetType resultSetType,
		boolean flushCache, boolean useCache, boolean resultOrdered, KeyGenerator keyGenerator, String keyProperty,
		String keyColumn, String databaseId, LanguageDriver lang, String resultSets) {

	if (unresolvedCacheRef) {
		throw new IncompleteElementException("Cache-ref not yet resolved");
	}

	id = applyCurrentNamespace(id, false);
	boolean isSelect = sqlCommandType == SqlCommandType.SELECT;

	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 statement = statementBuilder.build();
	configuration.addMappedStatement(statement);
	return statement;
}

statement对象的结构:

最后将statement设置到configuration中。

11、流程返回到3,返回设置的configuration对象:

configuration对象结构:

12、最后返回DefaultSqlSessionFactory类型的对象

总结:把配置文件的信息解析并保存在Configuration对象中,返回包含了ConfigurationDefaultSqlSession对象。

13、configuration对象中的重要属性

(1)MapperRegistry对象

(2)MappedStatement对象:代表一个增删改查的详细信息

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值