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

网友投稿 288 2023-02-13

详解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 lazyLoadTriggerMethods = new HashSet(

Arrays.asList(new String[] { "equals", "clone", "hashCode", "toStrinsNNvprRtBfg" }));

//默认执行语句超时

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 mappedStatements = new StrictMap(

"Mapped Statements collection");

//mapper_id和缓存的映射

protected final Map caches = new StrictMap("Caches collection");

//mapper_id和返回值的映射

protected final Map resultMaps = new StrictMap("Result Maps collection");

//mapper_id和参数的映射

protected final Map parameterMaps = new StrictMap("Parameter Maps collection");

//资源列表

protected final Set loadedResources = new HashSet();

未完.......

}

构建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 mappedStatements = new StrictMap(

"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 parameterMappings;

}

关于二级缓存

我们在Configuration中看到了一个caches属性

protected final Map 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) {sNNvprRtBf

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 selectOne(String statement);

T selectOne(String statement, Object parameter);

List selectList(String statement);

List selectList(String statement, Object parameter);

//其余增删查改方法略…

}

总结

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

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:信息流聚合(信息聚合技术)
下一篇:申请民宿平台api接口(民宿交流平台)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~