详解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 解析配置文件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!