MyBatis 3.5.4源码之旅四之mapper映射文件解析二
对照的流程图
XMLStatementBuilder的parseStatementNode解析sql语句
进行很多属性结点的获取,最后调用MapperBuilderAssistant
的addMappedStatement
创建MappedStatement
放入Configuration
中。内部会将sql语句配置的id
和全限定类名+id
全放进去,等于说是做了两个映射:
MapperAnnotationBuilder的parseStatement解析方法上的注解
MapperAnnotationBuilder的getSqlSourceFromAnnotations解析方法上的注解
他会去检查方法上是否有注释,如果既有sql
注解,又有sqlProvider
注解的话会报异常,只能解析一种,获取到注解上所有的sql
语句后,进行下一步解析:
MapperAnnotationBuilder的buildSqlSourceFromStrings解析注解sql
进行预处理,把多个sql
用空格拼起来。:
private SqlSource buildSqlSourceFromStrings(String[] strings, Class<?> parameterTypeClass, LanguageDriver languageDriver) {
final StringBuilder sql = new StringBuilder();
for (String fragment : strings) {
sql.append(fragment);
sql.append(" ");
}
return languageDriver.createSqlSource(configuration, sql.toString().trim(), parameterTypeClass);
}
XMLLanguageDriver的createSqlSource创建SqlSource
再进行SqlSource
的创建,当然具体里面还有很多细节,包括解析sql
,解析结果集映射等,我就不跟了,这里会创建是原始的sql
还是动态的sql
,动态的就是有占位符的:
@Override
public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
// issue #3
if (script.startsWith("<script>")) {
XPathParser parser = new XPathParser(script, false, configuration.getVariables(), new XMLMapperEntityResolver());
return createSqlSource(configuration, parser.evalNode("/script"), parameterType);
} else {
// issue #127
script = PropertyParser.parse(script, configuration.getVariables());
TextSqlNode textSqlNode = new TextSqlNode(script);
if (textSqlNode.isDynamic()) {
return new DynamicSqlSource(configuration, textSqlNode);
} else {
return new RawSqlSource(configuration, script, parameterType);
}
}
}
如果注解的sqlSource
不为空,下面还有一堆处理,简单来说就是封装好一个MappedStatement
,放入configuration.addMappedStatement(statement)
。后面真正用到的时候可以直接拿出来用,具体细节有兴趣可以慢慢看:
void parseStatement(Method method) {
Class<?> parameterTypeClass = getParameterType(method);
LanguageDriver languageDriver = getLanguageDriver(method);
SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
if (sqlSource != null) {
Options options = method.getAnnotation(Options.class);
final String mappedStatementId = type.getName() + "." + method.getName();
Integer fetchSize = null;
Integer timeout = null;
StatementType statementType = StatementType.PREPARED;
ResultSetType resultSetType = configuration.getDefaultResultSetType();
SqlCommandType sqlCommandType = getSqlCommandType(method);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = !isSelect;
boolean useCache = isSelect;
KeyGenerator keyGenerator;
String keyProperty = null;
String keyColumn = null;
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
// first check for SelectKey annotation - that overrides everything else
SelectKey selectKey = method.getAnnotation(SelectKey.class);
if (selectKey != null) {
keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
keyProperty = selectKey.keyProperty();
} else if (options == null) {
keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
} else {
keyGenerator = options.useGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
keyProperty = options.keyProperty();
keyColumn = options.keyColumn();
}
} else {
keyGenerator = NoKeyGenerator.INSTANCE;
}
if (options != null) {
if (FlushCachePolicy.TRUE.equals(options.flushCache())) {
flushCache = true;
} else if (FlushCachePolicy.FALSE.equals(options.flushCache())) {
flushCache = false;
}
useCache = options.useCache();
fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348
timeout = options.timeout() > -1 ? options.timeout() : null;
statementType = options.statementType();
if (options.resultSetType() != ResultSetType.DEFAULT) {
resultSetType = options.resultSetType();
}
}
String resultMapId = null;
ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);
if (resultMapAnnotation != null) {
resultMapId = String.join(",", resultMapAnnotation.value());
} else if (isSelect) {
resultMapId = parseResultMap(method);
}
assistant.addMappedStatement(
mappedStatementId,
sqlSource,
statementType,
sqlCommandType,
fetchSize,
timeout,
// ParameterMapID
null,
parameterTypeClass,
resultMapId,
getReturnType(method),
resultSetType,
flushCache,
useCache,
// TODO gcode issue #577
false,
keyGenerator,
keyProperty,
keyColumn,
// DatabaseID
null,
languageDriver,
// ResultSets
options != null ? nullOrEmpty(options.resultSets()) : null);
}
}
其他的三种方式其实都是类似的,缺不了这些:
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
resource
的:
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/RoleMapper.xml"/>
<mapper resource="mapper/AccountMapper.xml"/>
url
的:
<mapper url="file:///F:\ServerInfos\Mybatis\mybatis-3-master\src\main\resources\mapper\UserMapper.xml"/>
class
的:
<mapper class="com.ww.dao.UserDao"/>
<mapper class="com.ww.dao.AccountDao"/>
<mapper class="com.ww.dao.RoleDao"/>
至此parseConfiguration
工作完成,然后返回一个默认的DefaultSqlSessionFactory
,主要工作还是初始化Configuration
:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。