测试方法
public class UserMapperTest {
private UserMapper userMapper;
SqlSession sqlSession = null;
SqlSessionFactory sqlSessionFactory = null;
@Before
public void setUp() throws Exception {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//openSession(boolean autoCommit) 设置事务是否自动提交
sqlSession = sqlSessionFactory.openSession(true);
// 获取动态代理实现类
this.userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void testQueryUserById() {
User user = userMapper.queryUserById(1L);
System.out.println(user);
}
@Test
public void testQueryAll() {
List<User> users = userMapper.queryAll();
for (User user : users) {
System.out.println(user);
}
}
}
SqlSessionFactoryBuilder 的 build 方法提供了对Reader和 InputStream 两种类型的支持,并提供了Resources类简化配置文件的读取。
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder() {
}
public SqlSessionFactory build(Reader reader) {
return this.build((Reader)reader, (String)null, (Properties)null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return this.build((Reader)reader, environment, (Properties)null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return this.build((Reader)reader, (String)null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return this.build((InputStream)inputStream, environment, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return this.build((InputStream)inputStream, (String)null, properties);
}
//通过XMLConfigBuilder解析配置文件构建SqlSessionFactory对象
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
解析过程
// XMLConfigBuilder
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
// 解析mybatis配置文件根结点configuration
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
// 解析mybatis核心配置文件的子节点信息(properties、settings、typeAliases、plugins、mappers...)
private void parseConfiguration(XNode root) {
try {
// 解析properties节点
this.propertiesElement(root.evalNode("properties"));
// 解析settings节点
Properties settings = this.settingsAsProperties(root.evalNode("settings"));
this.loadCustomVfs(settings);
// 解析typeAliases类型别名节点
this.typeAliasesElement(root.evalNode("typeAliases"));
// 解析plugin节点
this.pluginElement(root.evalNode("plugins"));
// 解析objectFactory节点
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析reflectorFactory节点
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
// 解析environments节点
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
// 解析mappers节点
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
properties解析
可通过resource或url属性引用外部资源文件(两者不能同时存在),或使用property子元素配置
<!-- 引入外部资源配置文件 -->
<properties resource="jdbc.properties"/>
解析properties配置
// XMLConfigBuilder
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
Properties defaults = context.getChildrenAsProperties(); // 获取所有的property子节点
String resource = context.getStringAttribute("resource"); // 获取resource属性值
String url = context.getStringAttribute("url"); // 获取url属性值
if (resource != null && url != null) { //获取resource及url属性值 两者不能同时存在
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource)); // 将resource对应配置信息添加到defaults容器中
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url)); // 将url对应配置信息添加到defaults容器中
}
//获取全局配置文件Configuration已有变量 并添加至defaults容器中
Properties vars = this.configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
this.parser.setVariables(defaults);
this.configuration.setVariables(defaults); // 将proprties配置解析得到参数保存至全局配置类configuration的属性variables中
}
}
解析过程
- 首先解析properties的子节点property元素,将属性存入defaults容器。
- 然后解析properties上面的resource或url属性(两者不能同时存在),解析外部配置文件并存入defaults容器。
- 将defaults容器中所有配置信息添加到全局配置对象configuration中。
摘自mybatis官网
如果属性在不只一个地方进行了配置,那么MyBatis将按照下面的顺序来加载:
• 在 properties 元素体内指定的属性首先被读取。
• 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url
• 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的是 properties 属性中指定的属性。
typeAliases解析
可单独针对某个类型配置别名,也可以配置扫描包自动生成改包下所有类的别名(默认生成Bean首字母小写别名)
<typeAliases>
<!-- 别名 type 指定java对象类型 alias 别名名称 -->
<typeAlias type="com.laravelshao.learning.mybatis.pojo.User" alias="User"/>
</typeAliases>
<typeAliases>
<!-- 指定扫描包 Mybatis会将该包下所有类都生成别名(Bean首字母小写别名) -->
<package name="com.laravelshao.learning.mybatis.pojo"/>
</typeAliases>
解析typeAliases配置
// XMLConfigBuilder
private void typeAliasesElement(XNode parent) {
if (parent != null) {
Iterator var2 = parent.getChildren().iterator();
while(var2.hasNext()) {
XNode child = (XNode)var2.next();
String alias;
if ("package".equals(child.getName())) {
alias = child.getStringAttribute("name");
this.configuration.getTypeAliasRegistry().registerAliases(alias); //注册指定包下所有类
} else {
alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
this.typeAliasRegistry.registerAlias(clazz);
} else {
this.typeAliasRegistry.registerAlias(alias, clazz); //指定单独类的别名
}
} catch (ClassNotFoundException var7) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + var7, var7);
}
}
}
}
}
注册类型别名
// TypeAliasRegistry
public void registerAliases(String packageName) { // 注册指定包的类型别名
this.registerAliases(packageName, Object.class);
}
public void registerAliases(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil();
resolverUtil.find(new IsA(superType), packageName);
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
Iterator var5 = typeSet.iterator();
while(var5.hasNext()) {
Class<?> type = (Class)var5.next();
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
this.registerAlias(type);
}
}
}
public void registerAlias(String alias, Class<?> value) { // 注册指定类的别名
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
} else {
String key = alias.toLowerCase(Locale.ENGLISH);
if (this.TYPE_ALIASES.containsKey(key) && this.TYPE_ALIASES.get(key) != null && !((Class)this.TYPE_ALIASES.get(key)).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + ((Class)this.TYPE_ALIASES.get(key)).getName() + "'.");
} else {
this.TYPE_ALIASES.put(key, value);
}
}
}
plugins解析
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
• Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
• ParameterHandler (getParameterObject, setParameters)
• ResultSetHandler (handleResultSets, handleOutputParameters)
• StatementHandler (prepare, parameterize, batch, update, query)
分页插件PageHelper配置
<!-- 配置分页插件 PageHelper -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 设置数据库方言 -->
<property name="dialect" value="mysql"/>
<!-- 使用RowBounds分页是否进行count查询 默认false-->
<property name="rowBoundsWithCount" value="true"/>
</plugin>
</plugins>
解析plugins配置
// XMLConfigBuilder
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
Iterator var2 = parent.getChildren().iterator();
while(var2.hasNext()) {
XNode child = (XNode)var2.next();
String interceptor = child.getStringAttribute("interceptor"); // 获取interceptor属性值
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor)this.resolveClass(interceptor).newInstance(); // 创建Interceptor实例
interceptorInstance.setProperties(properties); // 设置属性
this.configuration.addInterceptor(interceptorInstance); //添加至Configuration的interceptorChain中
}
}
}
settings解析
可以设置mybatis运行时行为,包括设置二级缓存、延迟加载、按需加载、经典命名到驼峰命名映射等(下面为常用属性)。
设置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。 | true|false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。 | true|false | false |
aggressiveLazyLoading | 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods). | true|false | false(true in ≤3.4.1) |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true|false | false |
Settings解析并添加至全局配置类Configuration
// XMLConfigBuilder
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
} else {
Properties props = context.getChildrenAsProperties();
MetaClass metaConfig = MetaClass.forClass(Configuration.class, this.localReflectorFactory);
Iterator var4 = props.keySet().iterator();
Object key;
do {
if (!var4.hasNext()) {
return props;
}
key = var4.next();
} while(metaConfig.hasSetter(String.valueOf(key)));
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
private void settingsElement(Properties props) throws Exception {
this.configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
this.configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
this.configuration.setCacheEnabled(this.booleanValueOf(props.getProperty("cacheEnabled"), true));
this.configuration.setProxyFactory((ProxyFactory)this.createInstance(props.getProperty("proxyFactory")));
this.configuration.setLazyLoadingEnabled(this.booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
this.configuration.setAggressiveLazyLoading(this.booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
this.configuration.setMultipleResultSetsEnabled(this.booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
this.configuration.setUseColumnLabel(this.booleanValueOf(props.getProperty("useColumnLabel"), true));
this.configuration.setUseGeneratedKeys(this.booleanValueOf(props.getProperty("useGeneratedKeys"), false));
this.configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
this.configuration.setDefaultStatementTimeout(this.integerValueOf(props.getProperty("defaultStatementTimeout"), (Integer)null));
this.configuration.setDefaultFetchSize(this.integerValueOf(props.getProperty("defaultFetchSize"), (Integer)null));
this.configuration.setMapUnderscoreToCamelCase(this.booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
this.configuration.setSafeRowBoundsEnabled(this.booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
this.configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
this.configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
this.configuration.setLazyLoadTriggerMethods(this.stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
this.configuration.setSafeResultHandlerEnabled(this.booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
this.configuration.setDefaultScriptingLanguage(this.resolveClass(props.getProperty("defaultScriptingLanguage")));
Class<? extends TypeHandler> typeHandler = this.resolveClass(props.getProperty("defaultEnumTypeHandler"));
this.configuration.setDefaultEnumTypeHandler(typeHandler);
this.configuration.setCallSettersOnNulls(this.booleanValueOf(props.getProperty("callSettersOnNulls"), false));
this.configuration.setUseActualParamName(this.booleanValueOf(props.getProperty("useActualParamName"), true));
this.configuration.setReturnInstanceForEmptyRow(this.booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
this.configuration.setLogPrefix(props.getProperty("logPrefix"));
Class<? extends Log> logImpl = this.resolveClass(props.getProperty("logImpl"));
this.configuration.setLogImpl(logImpl);
this.configuration.setConfigurationFactory(this.resolveClass(props.getProperty("configurationFactory")));
}
mappers解析
mappers定义了mapper映射文件位置,可以使用类路径、url、全局类名或配置扫描包来引入。
<mappers>
<!-- 使用相对于类路径的资源引用 -->
<mapper resource="com/laravelshao/learning/mybatis/mapper/UserMapper.xml"/>
<!-- 使用完全限定资源定位符(URL) -->
<mapper url="file:///var/mappers/UserMapper.xml"/>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mapper class="com.laravelshao.learning.mybatis.mapper.UserMapper"/>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<package name="com.laravelshao.learning.mybatis.mapper"/>
</mappers>
mapper解析流程
// XMLConfigBuilder
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
Iterator var2 = parent.getChildren().iterator();
while(true) {
while(var2.hasNext()) {
XNode child = (XNode)var2.next();
String resource;
if ("package".equals(child.getName())) { // 如果是package子节点
resource = child.getStringAttribute("name"); // 获取package节点的name属性值(mapper class的包路径)
this.configuration.addMappers(resource); // 将所有的mapper class添加到configuration的mapperRegistry容器中
} else {
// mapper子节点 获取resource、url、class属性值
resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
XMLMapperBuilder mapperParser;
InputStream inputStream;
if (resource != null && url == null && mapperClass == null) { // 配置了resource属性
ErrorContext.instance().resource(resource);
inputStream = Resources.getResourceAsStream(resource);
// 使用XMLMapperBuilder解析mapper配置文件 并注册到configuration的mapperRegistry容器中
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) { // 配置了url属性
ErrorContext.instance().resource(url);
inputStream = Resources.getUrlAsStream(url);
mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
mapperParser.parse();
} else { // 配置了class属性
if (resource != null || url != null || mapperClass == null) {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
Class<?> mapperInterface = Resources.classForName(mapperClass); // 将全限定名转换为Class对象
this.configuration.addMapper(mapperInterface); // 注册到configuration的mapperRegistry容器中
}
}
}
return;
}
}
}
// XMLMapperBuilder
private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
super(configuration); // 将configuration赋值给BaseBuilder维护的全局configuration
this.builderAssistant = new MapperBuilderAssistant(configuration, resource); // 创建MapperBuilderAssistant对象
this.parser = parser;
this.sqlFragments = sqlFragments;
this.resource = resource;
}
// 解析mapper文件
public void parse() {
if (!this.configuration.isResourceLoaded(this.resource)) { // 若当前mapper还未加载 则执行解析
this.configurationElement(this.parser.evalNode("/mapper")); // 解析mapper配置元素
this.configuration.addLoadedResource(this.resource); // 添加到configuration的loadedResources容器
this.bindMapperForNamespace(); // 将当前mapper文件注册到configuration的mapperRegistry容器中
}
this.parsePendingResultMaps();
this.parsePendingCacheRefs();
this.parsePendingStatements();
}
configurationElement方法
// XMLMapperBuilder
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace != null && !namespace.equals("")) {
this.builderAssistant.setCurrentNamespace(namespace); // 将namespace设置到MapperBuilderAssistant中
this.cacheRefElement(context.evalNode("cache-ref")); // 解析cache-ref节点
this.cacheElement(context.evalNode("cache")); // 解析cache节点
this.parameterMapElement(context.evalNodes("/mapper/parameterMap")); // 解析parameterMap节点
this.resultMapElements(context.evalNodes("/mapper/resultMap")); // 解析resultMap
this.sqlElement(context.evalNodes("/mapper/sql")); // 解析sql节点
this.buildStatementFromContext(context.evalNodes("select|insert|update|delete")); // 解析具体sql节点
} else {
throw new BuilderException("Mapper's namespace cannot be empty");
}
} catch (Exception var3) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + this.resource + "'. Cause: " + var3, var3);
}
}
// XMLMapperBuilder
private void resultMapElements(List<XNode> list) throws Exception {
Iterator var2 = list.iterator();
while(var2.hasNext()) {
XNode resultMapNode = (XNode)var2.next();
try {
this.resultMapElement(resultMapNode);
} catch (IncompleteElementException var5) {
;
}
}
}
private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
return this.resultMapElement(resultMapNode, Collections.emptyList());
}
// 解析resultMap节点
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier()); // 获取resultMap节点的id属性
// 获取resultMap节点的type属性
String type = resultMapNode.getStringAttribute("type", resultMapNode.getStringAttribute("ofType", resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType"))));
String extend = resultMapNode.getStringAttribute("extends"); // 获取resultMap节点的extends属性
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping"); // 获取resultMap节点的autoMapping属性
Class<?> typeClass = this.resolveClass(type); // 将返回值类型转换为Class对象
Discriminator discriminator = null;
List<ResultMapping> resultMappings = new ArrayList();
resultMappings.addAll(additionalResultMappings); // 添加到resultMappings集合(存储resultMap的子节点)
List<XNode> resultChildren = resultMapNode.getChildren();
Iterator var11 = resultChildren.iterator();
while(var11.hasNext()) {
XNode resultChild = (XNode)var11.next();
if ("constructor".equals(resultChild.getName())) { // 解析constructor节点的子节点并添加resultMappings集合中
this.processConstructorElement(resultChild, typeClass, resultMappings);
} else if ("discriminator".equals(resultChild.getName())) { // 解析discriminator节点的子节点并添加resultMappings集合中
discriminator = this.processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {
List<ResultFlag> flags = new ArrayList();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);
}
resultMappings.add(this.buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
ResultMapResolver resultMapResolver = new ResultMapResolver(this.builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
return resultMapResolver.resolve();
} catch (IncompleteElementException var14) {
this.configuration.addIncompleteResultMap(resultMapResolver);
throw var14;
}
}
将sql语句解析为MappedStatement对象,并添加到全局configuration中
// XMLMapperBuilder
private void buildStatementFromContext(List<XNode> list) {
if (this.configuration.getDatabaseId() != null) {
this.buildStatementFromContext(list, this.configuration.getDatabaseId());
}
this.buildStatementFromContext(list, (String)null);
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
Iterator var3 = list.iterator();
while(var3.hasNext()) {
XNode context = (XNode)var3.next();
XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration, this.builderAssistant, context, requiredDatabaseId);
try {
statementParser.parseStatementNode();
} catch (IncompleteElementException var7) {
this.configuration.addIncompleteStatement(statementParser);
}
}
}
// XMLStatementBuilder
public void parseStatementNode() {
String id = this.context.getStringAttribute("id");
String databaseId = this.context.getStringAttribute("databaseId");
if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
Integer fetchSize = this.context.getIntAttribute("fetchSize");
Integer timeout = this.context.getIntAttribute("timeout");
String parameterMap = this.context.getStringAttribute("parameterMap");
String parameterType = this.context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = this.resolveClass(parameterType);
String resultMap = this.context.getStringAttribute("resultMap");
String resultType = this.context.getStringAttribute("resultType");
String lang = this.context.getStringAttribute("lang");
LanguageDriver langDriver = this.getLanguageDriver(lang);
Class<?> resultTypeClass = this.resolveClass(resultType);
String resultSetType = this.context.getStringAttribute("resultSetType");
StatementType statementType = StatementType.valueOf(this.context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
ResultSetType resultSetTypeEnum = this.resolveResultSetType(resultSetType);
String nodeName = this.context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = this.context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = this.context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = this.context.getBooleanAttribute("resultOrdered", false);
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(this.configuration, this.builderAssistant);
includeParser.applyIncludes(this.context.getNode());
this.processSelectKeyNodes(id, parameterTypeClass, langDriver);
SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);
String resultSets = this.context.getStringAttribute("resultSets");
String keyProperty = this.context.getStringAttribute("keyProperty");
String keyColumn = this.context.getStringAttribute("keyColumn");
String keyStatementId = id + "!selectKey";
keyStatementId = this.builderAssistant.applyCurrentNamespace(keyStatementId, true);
Object keyGenerator;
if (this.configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = this.configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = this.context.getBooleanAttribute("useGeneratedKeys", this.configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
// 使用MapperBuilderAssistant辅助类添加MappedStatement
this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
}
解析完成后会返回configuration对象,通过build(configuration)方法创建一个DefaultSqlSessionFactory
// SqlSessionFactoryBuilder
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config); // 创建默认实现DefaultSqlSessionFactory
}
自此,mybatis的初始化过程完成。
参考资料
http://www.mybatis.org/mybatis-3/zh/configuration.html
https://www.jianshu.com/p/7bc6d3b7fb45
http://www.cnblogs.com/dongying/tag/Mybatis%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA%E7%B3%BB%E5%88%97/
来源:oschina
链接:https://my.oschina.net/u/3249170/blog/1862419