从本文开始,我们来分享 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