详解Mybatis是如何解析配置文件的

作者:诺浅 时间:2023-10-15 23:23:40 

缘起

经过前面三章的入门,我们大概了解了Mybatis的主线逻辑是什么样子的,在本章中,我们将正式进入Mybatis的源码海洋。

Mybatis是如何解析xml的

构建Configuration

详解Mybatis是如何解析配置文件的

我们调用new SqlSessionFactoryBuilder().build()方法的最终目的就是构建 Configuration对象,那么Configuration何许人也?Configuration对象是一个配置管家, Configuration对象之中维护着所有的配置信息。
Configuration的代码片段如下


public class Configuration {
//环境
protected Environment environment;
protected boolean safeRowBoundsEnabled;
protected boolean safeResultHandlerEnabled = true;
protected boolean mapUnderscoreToCamelCase;
protected boolean aggressiveLazyLoading;
protected boolean multipleResultSetsEnabled = true;
protected boolean useGeneratedKeys;
protected boolean useColumnLabel = true;
protected boolean cacheEnabled = true;
protected boolean callSettersOnNulls;
protected boolean useActualParamName = true;
protected boolean returnInstanceForEmptyRow;

//日志信息的前缀
protected String logPrefix;

//日志接口
protected Class<? extends Log> logImpl;

//文件系统接口
protected Class<? extends VFS> vfsImpl;

//本地Session范围
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;

//数据库类型
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;

//延迟加载的方法
protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(
  Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));

//默认执行语句超时
protected Integer defaultStatementTimeout;

//默认的执行器
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

//数据库ID
protected String databaseId;

//mapper注册表
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);

// * 链
protected final InterceptorChain interceptorChain = new InterceptorChain();

//类型处理器
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();

//类型别名
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();

//语言驱动
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

//mapper_id 和 mapper文件的映射
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
  "Mapped Statements collection");

//mapper_id和缓存的映射
protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");

//mapper_id和返回值的映射
protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");

//mapper_id和参数的映射
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");

//资源列表
protected final Set<String> loadedResources = new HashSet<String>();

未完.......
}

构建MappedStatement

在Configuration中,有个mappedStatements的属性,这是个MappedStatement对象Map的集合,其key是这个mapper的namespace+对应节点的id,而value是一个MappedStatement对象。
在构建Configuration的时候,会去解析我们的配置文件。
解析配置文件的关键代码如下


private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}

上诉代码段倒数第三行mapperElement(root.evalNode("mappers"));就是解析mappers处就是把我们的mapper文件封装成MappedStatement对象,然后保存到Configuration的mappedStatements属性中,其中key是这个mapper的namespace+对应节点的id,而value是一个MappedStatement对象。保存的地方关键代码如下


configuration.addMappedStatement(statement);

addMappedStatement()方法代码如下


protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
  "Mapped Statements collection");

public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}

那么这个MappedStatement的又是何许人也?我们可以简单的把MapperStatement理解为对sql的一个封装,在MappedStatement中保存着一个SqlSource对象,其中就存有SQL的信息。相关代码如下


public final class MappedStatement {
private SqlSource sqlSource;
}

SqlSource 代码如下


public interface SqlSource {
BoundSql getBoundSql(Object parameterObject);
}

BoundSql代码如下


public class BoundSql {
private final String sql;
private final List<ParameterMapping> parameterMappings;
}

关于二级缓存
我们在Configuration中看到了一个caches属性


protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");

这个东西的作用是什么呢?其实是关于Mybatis的二级缓存的。在解析配置文件的过程中,如果用到了二级缓存,便会把这个ID和对象也保存到configuration的caches中,相关代码如下


public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}

构建SqlSessionFactory

在Configuration对象构建完毕之后,就该依赖Configuration对象去构建SqlSessionFactory对象了,相关代码如下


public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}

我们暂且把SqlSessionFactory称为SqlSession工厂吧,SqlSessionFactory中有两个方法,openSession()和getConfiguration()
SqlSessionFactory代码如下


public interface SqlSessionFactory {
SqlSession openSession();
//其余openSession重载方法略…
Configuration getConfiguration();
}

构建SqlSession

openSession()方法会返回一个SqlSession对象,SqlSession又是何许人也?SqlSession可以理解为程序与数据库打交道的一个工具,通过它,程序可以往数据库发送SQL执行。
SqlSession代码如下


public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
//其余增删查改方法略…
}

来源:https://blog.csdn.net/qq32933432/article/details/104351587

标签:Mybatis,配置文件
0
投稿

猜你喜欢

  • Spring MVC 简单的hello world的实现

    2023-06-18 02:56:41
  • SpringBoot与Postman实现REST模拟请求的操作

    2022-12-22 04:06:14
  • TextView显示系统时间(时钟功能带秒针变化

    2022-04-23 08:07:37
  • Android自定义View多种效果解析

    2022-05-26 06:59:46
  • Android发布项目到jitpack的完整步骤

    2021-11-29 08:42:10
  • c# 如何实现图片压缩

    2022-02-10 00:46:31
  • Java使用entrySet方法获取Map集合中的元素

    2022-08-06 17:41:05
  • C#探秘系列(一)——ToDictionary,ToLookup

    2023-04-19 09:16:15
  • Android自定义View实现微信语音界面

    2022-03-27 20:35:27
  • java如何读取超大文件

    2022-10-24 08:20:54
  • Android开发之自定义刮刮卡实现代码

    2023-07-30 14:52:57
  • C#中数组初始化与数组元素复制的方法

    2023-05-14 15:45:06
  • C#入门教程之集合ArrayList用法详解

    2022-04-30 06:32:13
  • Android自定义view实现TextView方形输入框

    2021-09-16 17:09:33
  • SpringBoot+WebSocket实现消息推送功能

    2021-11-15 12:16:18
  • C#基础入门之值类型和引用类型的区别详析

    2022-02-22 00:14:04
  • Android桌面插件App Widget用法分析

    2022-02-05 02:26:39
  • 一文彻底搞懂Kotlin中的协程

    2021-09-19 19:16:01
  • 详解C#中的定时器Timer类及其垃圾回收机制

    2021-07-21 10:57:39
  • Java字母加数字组合比较大小

    2023-02-27 15:27:52
  • asp之家 软件编程 m.aspxhome.com