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

 更新时间:2020年12月16日 11:00:06   作者:诺浅  
这篇文章主要介绍了详解Mybatis是如何解析配置文件的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

缘起

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

Mybatis是如何解析xml的

构建Configuration

在这里插入图片描述

我们调用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);
 //其余增删查改方法略…
}

总结

想必你已经明白了,Mybatis解析xml最主要的目的其实是构建Configuration对象,这个对象中可以说包含着Mybatis的所有配置信息。其中有一个mappedStatements属性,这是一个Map,其中key是这个mapper的namespace+对应节点的id,而value是一个MappedStatement对象,而MappedStatement中保存着一个SqlSource对象,这个对象中保存着我们要执行的SQL语句。

那么在下一章,我们将一起探究Mybatis是如何执行我们的SQL语句的。

到此这篇关于详解Mybatis是如何解析配置文件的的文章就介绍到这了,更多相关Mybatis 解析配置文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot事务失效的原因及解决办法详解

    Springboot事务失效的原因及解决办法详解

    这篇文章主要介绍了Springboot事务失效的原因及解决办法详解,spring中的事务是依赖AOP的,AOP是通过动态代理实现的,只有通过代理类访问的方法才能被拦截,而addMultiFile直接内部调用了addFile方法,所以addFile中的事务就不会生效
    2023-10-10
  • 浅析如何高效格式化输出JSON字符串

    浅析如何高效格式化输出JSON字符串

    JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,已经成为了各种编程语言间传递数据的标准,下面我们就来聊聊如何高效格式化输出JSON字符串吧
    2025-01-01
  • SpringBoot导入Druid运行失败问题

    SpringBoot导入Druid运行失败问题

    这篇文章主要介绍了SpringBoot导入Druid运行失败,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • java程序代码与文本对比实用工具简介

    java程序代码与文本对比实用工具简介

    可以对两段文本进行对比,检测/比较两个文本有什么不同的差异,以便修改,常用于程序代码,就是不需要人工查看,尤其是大文件,有几百上千行的代码,这时候就建议使用比较工具了,不用浪费过多时间去寻找
    2021-09-09
  • List集合多线程并发条件下不安全如何解决

    List集合多线程并发条件下不安全如何解决

    List是我们常用的集合,但是在多线程并发的条件下,会出现安全问题吗?下面我们就来测试一下,如果出现安全问题,该如何解决,感兴趣的可以了解一下
    2021-12-12
  • springboot应用服务启动事件的监听实现

    springboot应用服务启动事件的监听实现

    本文主要介绍了springboot应用服务启动事件的监听实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • java使用WatchService监控文件夹示例

    java使用WatchService监控文件夹示例

    本篇文章主要介绍了java使用WatchService监控文件夹示例的资料,这里整理了详细的代码,有需要的小伙伴可以参考下。
    2017-02-02
  • Spring Boot利用Thymeleaf发送Email的方法教程

    Spring Boot利用Thymeleaf发送Email的方法教程

    spring Boot默认就是使用thymeleaf模板引擎的,下面这篇文章主要给大家介绍了关于在Spring Boot中利用Thymeleaf发送Email的方法教程,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-08-08
  • dom4j操作xml的demo(分享)

    dom4j操作xml的demo(分享)

    下面小编就为大家带来一篇dom4j操作xml的demo(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 带你全面认识Java中的异常处理

    带你全面认识Java中的异常处理

    在你所写过的代码中,你已经接触过一些异常了,我们可以通过一些简单的代码让我们理解一些简单的异常,下面这篇文章主要给大家介绍了关于Java中异常处理的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-12-12

最新评论