文章目录
- Configuration概述
- Configuration的核心作用与配置来源
- 配置元素
- 元素承载
- 配置文件解析
- XML文件解析流程
- 注解配置解析
Configuration概述
Configuration 是整个MyBatis的配置体系集中管理中心,前文所说的Executor、StatementHandler、Cache、MappedStatement…等绝大部分组件都是由它直接或间接的创建和管理。此外影响这些组件行为的属性配置也是由它进行保存和维护。如cacheEnabled、lazyLoadingEnabled … 等。所以说它MyBatis的大管家很形象。
Configuration是MyBatis中极其重要的一个类,它代表MyBatis的全局配置信息。
Configuration中包含了很多关键信息,主要包括:
- environments:存储了多个环境信息,每个环境都有transactionFactory和dataSource;
- mappers:存储了所有mapper文件的位置信息;
- mappedStatements:存储了所有mappedStatement的信息,每个mappedStatement代表一条SQL语句;
- resultMaps:存储了所有resultMap的信息,resultMap代表结果集映射;
- parameterMap:旧版本使用,已废弃;
- keyGenerators:存储了所有keyGenerator的信息,keyGenerator用于生成主键;
- typeHandlers:存储了所有typeHandler的信息,typeHandler用于javaType和jdbcType之间的转换;
- objectFactory:对象工厂,用于实例化目标对象;
- objectWrapperFactory:对象包装工厂,用于给目标对象创建代理对象;
- interceptors:存储了所有Interceptor的信息,Interceptor用于拦截器执行SQL;
- databaseIdProvider:根据databaseId获取对应的mappedStatement;
- logImpl:日志工厂;
- cache:缓存命名空间;
- 等等。
Configuration保存的所有这些信息构成了MyBatis一次会话(SqlSession)的全部配置环境。每开启一个新的 SqlSession 都会根据 Configuration 来构建出 SqlSession 需要的所有信息。
所以简而言之,Configuration存储了MyBatis的全局配置信息,代表了一个MyBatis配置环境,它包含了SQL映射语句、结果集映射、缓存机制等等信息,这些信息构成了一个MyBatis一次会话需要的所有配置内容。
-
当我们调用
SqlSessionFactoryBuilder.build(reader)
构建SqlSessionFactory时,底层会根据配置文件来构建一个Configuration对象。 -
当我们调用
openSession()
开启一个会话时,SqlSession由一个Configuration以及执行器(Executor)组成,这个Configuration就是前面构建的全局配置信息。
所以可以看出,Configuration对MyBatis来说意义重大,它包含了MyBatis会话所需要的全部配置资源和环境信息。没有Configuration,则根本无法构建SqlSession,也就无法工作了。
Configuration的核心作用与配置来源
Configuration 配置来源有三项:
- Mybatis-config.xml 启动文件,全局配置、全局组件都是来源于此。
- Mapper.xml SQL映射(MappedStatement) \结果集映射(ResultMapper)都来源于此。
- @Annotation SQL映射与结果集映射的另一种表达形式。
然后我们再说说Configuration的核心作用:
- 存储全局配置信息,其来源于settings(设置)
- 初始化并维护全局基础组件
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- plugins(插件)
- environments(环境配置)
- cache(二级缓存空间)
- 初始化并维护MappedStatement
- 组件构造器,并基于插件进行增强
- newExecutor(执行器)
- newStatementHandler(JDBC处理器)
- newResultSetHandler(结果集处理器)
- newParameterHandler(参数处理器)
这里我们为什么要使用Configuration进行Executor的创建?原因如下:
1、根据配置的类型创建
2、是否开启缓存
3、使用interceptorChain引入插件
这样做到了统一的包装,标准化创建组件。
其他几个组件的创建也是一样:
我们来说说几个组件:
mapperRegistry
用来注册mapper接口,并生成其动态代理对象。
caches
缓存,应用级跨会话的,所有的缓存装载好了之后都会放在Configuration里面。然后mappedStatement会与我们的缓存做一个关联操作,并且他们俩之间是1:1的关系。
TypeAliasRegistry
TypeAliasRegistry是MyBatis中用于保存类型别名的注册中心。
在MyBatis中,我们可以使用<typeAlias>
标签来为Java类型配置别名,如:
<typeAlias type="com.someapp.model.User" alias="User"/>
这会使User成为com.someapp.model.User类型的别名,在后续映射文件中可以直接使用User来代表那个类型。
那么,MyBatis是如何实现这个类型别名功能的呢?
这就要依赖TypeAliasRegistry了
- TypeAliasRegistry中保存了所有的类型别名配置。当我们的SQL映射文件被解析时,MyBatis会查找其中的
<typeAlias>
配置,并将找到的类型别名注册到这个注册中心。 - 然后,在后续的解析过程中,每当MyBatis遇到一个类型时,它会首先检查TypeAliasRegistry是否存在该类型的别名,如果存在则使用该别名,否则使用全限定名。
所以,TypeAliasRegistry的作用就是用来保存类型别名配置,并让MyBatis在需要时可以查找并使用这些别名。它实现了MyBatis的类型别名功能。
TypeAliasRegistry作为MyBatis的核心组件之一,主要有以下作用:
- 保存类型别名配置:MyBatis可以在其中注册从映射文件中解析得到的类型别名,以备后续查找和使用。
- 查找别名:在MyBatis的解析过程中,每当需要一个类型时,MyBatis会首先在TypeAliasRegistry中查找该类型的别名。如果存在,则使用别名,否则使用全限定名。
- 简化配置:通过类型别名,可以简化MyBatis的映射配置。我们无需在每次使用一个类型时都输入其完整的限定名,只需要使用MyBatis为其配置的别名即可,这提高了配置的可读性和效率。
- 减少解析次数:每次MyBatis使用一个别名而非全限定名,可以减少一次对那个包的解析,这可以稍微提高MyBatis的解析性能。
配置元素
Configuration 配置信息来源于xml和注解,每个文件和注解都是由若干个配置元素组成,并呈现嵌套关系,总体关系如下图所示:
关于各配置的使用请参见官网给出文档:https://mybatis.org/mybatis-3/zh/configuration.html#properties
元素承载
无论是XML还是我注解这些配置元素最弱都要被转换成JAVA配置属性或对象组件来承载。其对应关系如下:
- 全配置(config.xml) 由Configuration对象属性承载
- sql映射
<select|insert...>
或@Select
等由MappedStatement对象承载 - 缓存
<cache..>
或@CacheNamespace
由Cache对象承载 - 结果集映射 由ResultMap 对象承载
配置文件解析
XML文件解析流程
配置文件解析需要我们分开讨论,首先来分析XML解析过程。xml配置解析其底层使用dom4j先解析成一棵节点树,然后根据不同的节点类型与去匹配不同的解析器。最终解析成特定组件。
解析器的基类是BaseBuilder 其内部包含全局的Configuration 对象,这么做的用意是所有要解析的组件最后都要集中归属至Configuration。接下来了解一下每个解析器的作用:
- XMLConfigBuilder :解析config.xml文件,会直接创建一个Configuration对象,用于解析全局配置 。
- XMLMapperBuilder :解析Mapper.xml文件,内容包含 等
- MapperBuilderAssistant:Mapper.xml解析辅助,在一个Mapper.xml中Cache是对Statement(sql声明)共享的,共享组件的分配即由该解析实现。
- XMLStatementBuilder:SQL映射解析 即<select|update|insert|delete> 元素解析成MapperStatement。
- SqlSourceBuilder:Sql数据源解析,将声明的SQL解析可执行的SQL。
- XMLScriptBuilder:解析动态SQL数据源当中所设置 SqlNode脚本集。
整体解析流程是从XmlConfigBuilder 开始,然后逐步向内解析,直到解析完所有节点。我们通过一个MappedStatement 解析过程即可了解到其整体解析流程。
流程说明:
-
【XmlConfigBuilder】 接收一个config.xml 输入流,然后创建一个空Configuration对象
-
【XmlConfigBuilder】解析全局配置
-
【XmlConfigBuilder】mapperElements解析,通过Resource或url 指定mapper.xml文件
- 【XmlMapperBuilder】解析缓存、结果集配置等公共配置
- 【XmlMapperBuilder】解析Sql映射<select|insert|upate|delete>
- 【XMLScriptBuilder】解析生成SQL数据源,包括动态脚本
- 【XmlMapperBuilder】构建Statement
- 【MapperBuilderAssistant】设置缓存并添加至Configuration
注解配置解析
注解解析底层实现是通过反射获取Mapper接口当中注解元素实现。有两种方式:
- 一种是直接指定接口名
- 一种是指定包名然后自动扫描包下所有的接口类
这些逻辑均由Mapper注册器(MapperRegistry)实现。其接收一个接口类参数,并基于该参数创建针对该接口的动态代理工厂,然后解析内部方法注解生成每个MapperStatement 最后添加至Configuration 完成解析。
想了解更多可参考文章:
MyBatis 核心配置综述之 Configuration详解
Mybatis主配置—Configuration