从本文开始,我们来分享 MyBatis 初始化的流程。在 《精尽 MyBatis 源码分析 —— 项目结构一览》 中,我们简单介绍这个流程如下:
在 MyBatis 初始化过程中,会加载
mybatis-config.xml配置文件、映射配置文件以及 Mapper 接口中的注解信息,解析后的配置信息会形成相应的对象并保存到 Configuration 对象中。例如:
<resultMap>节点(即 ResultSet 的映射规则) 会被解析成 ResultMap 对象。<result>节点(即属性映射)会被解析成 ResultMapping 对象。之后,利用该 Configuration 对象创建 SqlSessionFactory对象。待 MyBatis 初始化之后,开发人员可以通过初始化得到 SqlSessionFactory 创建 SqlSession 对象并完成数据库操作。
builder 模块,为配置解析过程mapping 模块,主要为 SQL 操作解析后的映射。因为整个 MyBatis 的初始化流程涉及代码颇多,所以拆分成三篇文章:
mybatis-config.xml 配置文件。本文就主要分享第一部分「加载 mybatis-config.xml 配置文件」。
MyBatis 的初始化流程的入口是 SqlSessionFactoryBuilder 的 #build(Reader reader, String environment, Properties properties) 方法,代码如下:
SqlSessionFactoryBuilder 中,build 方法有多种重载方式。这里就选取一个。
// SqlSessionFactoryBuilder.java
|
<1> 处,创建 XMLConfigBuilder 对象。<2> 处,调用 XMLConfigBuilder#parse() 方法,执行 XML 解析,返回 Configuration 对象。<3> 处,创建 DefaultSqlSessionFactory 对象。<1> 和 <2> 处,即 XMLConfigBuilder 类。详细解析,见 「3. XMLConfigBuilder」 。org.apache.ibatis.builder.BaseBuilder ,基础构造器抽象类,为子类提供通用的工具类。
为什么不直接讲 XMLConfigBuilder ,而是先讲 BaseBuilder 呢?因为,BaseBuilder 是 XMLConfigBuilder 的父类,并且它还有其他的子类。如下图所示:
// BaseBuilder.java
|
configuration 属性,MyBatis Configuration 对象。XML 和注解中解析到的配置,最终都会设置到 org.apache.ibatis.session.Configuration 中。感兴趣的胖友,可以先点击瞅一眼。抽完之后,马上回来。#parseExpression(String regex, String defaultValue) 方法,创建正则表达式。代码如下:
// BaseBuilder.java
|
#xxxValueOf(...) 方法,将字符串转换成对应的数据类型的值。代码如下:
// BaseBuilder.java
|
#resolveJdbcType(String alias) 方法,解析对应的 JdbcType 类型。代码如下:
// BaseBuilder.java
|
#resolveResultSetType(String alias) 方法,解析对应的 ResultSetType 类型。代码如下:
// BaseBuilder.java
|
#resolveParameterMode(String alias) 方法,解析对应的 ParameterMode 类型。代码如下:
// BaseBuilder.java
|
#createInstance(String alias) 方法,创建指定对象。代码如下:
// BaseBuilder.java
|
<1> 处,调用 #resolveClass(String alias) 方法,获得对应的类型。代码如下:
// BaseBuilder.java
|
typeAliasRegistry 中,通过别名或类全名,获得对应的类。<2> 处,创建对象。#resolveTypeHandler(Class<?> javaType, String typeHandlerAlias) 方法,从 typeHandlerRegistry 中获得或创建对应的 TypeHandler 对象。代码如下:
// BaseBuilder.java
|
org.apache.ibatis.builder.xml.XMLConfigBuilder ,继承 BaseBuilder 抽象类,XML 配置构建器,主要负责解析 mybatis-config.xml 配置文件。即对应 《MyBatis 文档 —— XML 映射配置文件》 。
// XMLConfigBuilder.java
|
parser 属性,XPathParser 对象。在 《精尽 MyBatis 源码分析 —— 解析器模块》 中,已经详细解析。localReflectorFactory 属性,DefaultReflectorFactory 对象。在 《精尽 MyBatis 源码分析 —— 反射模块》 中,已经详细解析。构造方法重载了比较多,只需要看最后一个。
<1> 处,创建 Configuration 对象。<2> 处,设置 Configuration 对象的 variables 属性。代码如下:
// Configuration.java
|
#parse() 方法,解析 XML 成 Configuration 对象。代码如下:
// XMLConfigBuilder.java
|
<1.1> 处,若已解析,抛出 BuilderException 异常。<1.2> 处,标记已解析。<2> 处,调用 XPathParser#evalNode(String expression) 方法,获得 XML <configuration /> 节点,后调用 #parseConfiguration(XNode root) 方法,解析该节点。详细解析,见 「3.3 parseConfiguration」 。#parseConfiguration(XNode root) 方法,解析 <configuration /> 节点。代码如下:
// XMLConfigBuilder.java
|
<1> 处,调用 #propertiesElement(XNode context) 方法,解析 <properties /> 节点。详细解析,见 「3.3.1 propertiesElement」 。<2> 处,调用 #settingsAsProperties(XNode context) 方法,解析 <settings /> 节点。详细解析,见 「3.3.2 settingsAsProperties」 。<3> 处,调用 #loadCustomVfs(Properties settings) 方法,加载自定义 VFS 实现类。详细解析,见 「3.3.3 loadCustomVfs」 。<4> 处,调用 #typeAliasesElement(XNode parent) 方法,解析 <typeAliases /> 节点。详细解析,见 「3.3.4 typeAliasesElement」 。<5> 处,调用 #typeAliasesElement(XNode parent) 方法,解析 <plugins /> 节点。详细解析,见 「3.3.5 pluginElement」 。<6> 处,调用 #objectFactoryElement(XNode parent) 方法,解析 <objectFactory /> 节点。详细解析,见 「3.3.6 pluginElement」 。<7> 处,调用 #objectWrapperFactoryElement(XNode parent) 方法,解析 <objectWrapperFactory /> 节点。详细解析,见 「3.3.7 objectWrapperFactoryElement」 。<8> 处,调用 #reflectorFactoryElement(XNode parent) 方法,解析 <reflectorFactory /> 节点。详细解析,见 「3.3.8 reflectorFactoryElement」 。<9> 处,调用 #settingsElement(Properties props) 方法,赋值 <settings /> 到 Configuration 属性。详细解析,见 「3.3.9 settingsElement」 。<10> 处,调用 #environmentsElement(XNode context) 方法,解析 <environments /> 标签。详细解析,见 「3.3.10 environmentsElement」 。<11> 处,调用 #databaseIdProviderElement(XNode context) 方法,解析 <databaseIdProvider /> 标签。详细解析,见 「3.3.11 databaseIdProviderElement」 。<12> 处,调用 #typeHandlerElement(XNode context) 方法,解析 <typeHandlers /> 标签。详细解析,见 「3.3.12 typeHandlerElement」 。<13> 处,调用 #mapperElement(XNode context) 方法,解析 <mappers /> 标签。详细解析,见 「3.3.13 mapperElement」 。#propertiesElement(XNode context) 方法,解析 <properties /> 节点。大体逻辑如下:
<properties /> 标签,成 Properties 对象。configuration 中的 Properties 对象到上面的结果。parser 和 configuration 中。代码如下:
// XMLConfigBuilder.java
|
#settingsElement(Properties props) 方法,将 <setting /> 标签解析为 Properties 对象。代码如下:
// XMLConfigBuilder.java
|
#loadCustomVfs(Properties settings) 方法,加载自定义 VFS 实现类。代码如下:
// XMLConfigBuilder.java
|
#typeAliasesElement(XNode parent) 方法,解析 <typeAliases /> 标签,将配置类注册到 typeAliasRegistry 中。代码如下:
// XMLConfigBuilder.java
|
#pluginElement(XNode parent) 方法,解析 <plugins /> 标签,添加到 Configuration#interceptorChain 中。代码如下:
// XMLConfigBuilder.java
|
<1> 处,创建 Interceptor 对象,并设置属性。关于 Interceptor 类,后续文章,详细解析。<2> 处,调用 Configuration#addInterceptor(Interceptor interceptor) 方法,添加到 configuration 中。代码如下:
// Configuration.java
|
#objectFactoryElement(XNode parent) 方法,解析 <objectFactory /> 节点。代码如下:
// XMLConfigBuilder.java
|
<1> 处,创建 ObjectFactory 对象,并设置 Properties 属性。<2> 处,调用 Configuration#setObjectFactory(ObjectFactory objectFactory) 方法,设置 Configuration 的 objectFactory 属性。代码如下:
// Configuration.java
|
#objectWrapperFactoryElement(XNode context) 方法,解析 <objectWrapperFactory /> 节点。代码如下:
// XMLConfigBuilder.java
|
<1> 处,创建 ObjectWrapperFactory 对象。<2> 处,调用 Configuration#setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) 方法,设置 Configuration 的 objectWrapperFactory 属性。代码如下:
// Configuration.java
|
#reflectorFactoryElement(XNode parent) 方法,解析 <reflectorFactory /> 节点。代码如下:
// XMLConfigBuilder.java
|
<1> 处,创建 ReflectorFactory 对象。<2> 处,调用 Configuration#setReflectorFactory(ReflectorFactory reflectorFactory) 方法,设置 Configuration 的 reflectorFactory 属性。代码如下:
// Configuration.java
|
#settingsElement(Properties props) 方法,赋值 <settings /> 到 Configuration 属性。代码如下:
// XMLConfigBuilder.java
|
#environmentsElement(XNode context) 方法,解析 <environments /> 标签。代码如下:
// XMLConfigBuilder.java
|
<1> 处,若 environment 属性非空,从 default 属性种获得 environment 属性。<2> 处,遍历 XNode 节点,获得其 id 属性,后调用 #isSpecifiedEnvironment(String id) 方法,判断 environment 和 id 是否匹配。代码如下:
// XMLConfigBuilder.java
|
<3> 处,调用 #transactionManagerElement(XNode context) 方法,解析 <transactionManager /> 标签,返回 TransactionFactory 对象。代码如下:
// XMLConfigBuilder.java
|
<4> 处,调用 #dataSourceElement(XNode context) 方法,解析 <dataSource /> 标签,返回 DataSourceFactory 对象,而后返回 DataSource 对象。代码如下:
// XMLConfigBuilder.java
|
<5> 处,创建 Environment.Builder 对象。
<6> 处,构造 Environment 对象,并设置到 configuration 中。代码如下:
// Configuration.java
|
org.apache.ibatis.mapping.Environment ,DB 环境。代码如下:
// Environment.java
|
#databaseIdProviderElement(XNode context) 方法,解析 <databaseIdProvider /> 标签。代码如下:
// XMLConfigBuilder.java
|
<1> 处,获得 DatabaseIdProvider 的类。<2> 处,获得 Properties 对象。<3> 处,创建 DatabaseIdProvider 对象,并设置对应的属性。<4> 处,调用 DatabaseIdProvider#getDatabaseId(DataSource dataSource) 方法,获得对应的 databaseId 标识。<5> 处,设置到 configuration 中。代码如下:
// Configuration.java
|
org.apache.ibatis.mapping.DatabaseIdProvider ,数据库标识提供器接口。代码如下:
public interface DatabaseIdProvider {
|
org.apache.ibatis.mapping.VendorDatabaseIdProvider ,实现 DatabaseIdProvider 接口,供应商数据库标识提供器实现类。
① 构造方法
// VendorDatabaseIdProvider.java
|
② 获得数据库标识
#getDatabaseId(DataSource dataSource) 方法,代码如下:
// VendorDatabaseIdProvider.java
|
<1> 处,调用 #getDatabaseProductName(DataSource dataSource) 方法,获得数据库产品名。代码如下:
// VendorDatabaseIdProvider.java
|
<2> 处,如果 properties 非空,则从 properties 中匹配 KEY ?若成功,则返回 VALUE ,否则,返回 null 。<3> 处,如果 properties 为空,则直接返回 productName 。#typeHandlerElement(XNode parent) 方法,解析 <typeHandlers /> 标签。代码如下:
// XMLConfigBuilder.java
|
<1> 是 <package /> 和 <2> 是 <typeHandler /> 两种标签的情况。逻辑比较简单,最终都是注册到 typeHandlerRegistry 中。#mapperElement(XNode context) 方法,解析 <mappers /> 标签。代码如下:
// XMLConfigBuilder.java
|
<0> 处,遍历子节点,处理每一个节点。根据节点情况,会分成 <1>、<2>、<3>、<4> 种情况,并且第一个是处理 <package /> 标签,后三个是处理 <mapper /> 标签。<1> 处,如果是 <package /> 标签,则获得 name 报名,并调用 Configuration#addMappers(String packageName) 方法,扫描该包下的所有 Mapper 接口。代码如下:
// Configuration.java
|
<4> 处,如果是 mapperClass 非空,则是使用映射器接口实现类的完全限定类名,则获得 Mapper 接口,并调用 Configuration#addMapper(Class<T> type) 方法,直接添加到 configuration 中。代码如下:
// Configuration.java
|
<1> 和 <4> 是相似情况,差别在于前者需要扫描,才能获取到所有的 Mapper 接口,而后者明确知道是哪个 Mapper 接口。<2> 处,如果是 resource 非空,则是使用相对于类路径的资源引用,则需要创建 XMLMapperBuilder 对象,并调用 XMLMapperBuilder#parse() 方法,执行解析 Mapper XML 配置。执行之后,我们就能知道这个 Mapper XML 配置对应的 Mapper 接口。关于 XMLMapperBuilder 类,我们放在下一篇博客中,详细解析。<3> 处,如果是 url 非空,则是使用完全限定资源定位符(URL),情况和 <2> 是类似的mybatis初始化加载mybatis-config.xml文件
原文:https://www.cnblogs.com/siye1989/p/11622110.html