Config文件解析
涉及的主要类:
- BaseBuilder
- XMLConfigBuilder
- Interceptor
- ObjectFactory
- ObjectWrapperFactory
- ReflectorFactory
- TransactionFactory
- DataSourceFactory
- DataSource
- Environment
- XMLMapperBuilder
- Cache
- ResultMap
- ResultMapping
- XMLStatementBuilder
- SqlSource
- LanguageDriver
- XMLScriptBuilder
- MapperBuilderAssistant
1、mybatis-config.xml文件结构
<configuration>
<!-- 加载属性配置文件-->
<properties resource="org/apache/ibatis/databases/blog/blog-derby.properties"/>
<!--全局配置信息-->
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="false"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
</settings>
<!--配置别名信息,在映射配置文件中可以直接使用Author来代替org.apache.ibatis.domain.blog.Author类-->
<typeAliases>
<typeAlias alias="Author" type="org.apache.ibatis.domain.blog.Author"/>
</typeAliases>
<!--自定义TypeHandler,在数据库类型和对象类型转化时使用-->
<typeHandlers>
<typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
</typeHandlers>
<!--对象工厂-->
<objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory">
<property name="objectFactoryProperty" value="100"/>
</objectFactory>
<!--自定义插件-->
<plugins>
<plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
<property name="pluginProperty" value="100"/>
</plugin>
</plugins>
<!--数据库环境相关配置-->
<environments default="development">
<environment id="development">
<!--数据库事务管理器的类型-->
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<!--数据库源类型以及数据连接相关信息-->
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--映射配置文件的路径-->
<mappers>
<mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/>
</mappers>
</configuration>
2、配置文件解析
- 入口:SqlSessionFactoryBuilder
- 通过XMLConfigBuilder解析配置文件并初始化Configuration
- 创建SqlSessionFactory(实际为DefaultSqlSessionFactory)【持有Configuration对象】
- 通过DefaultSqlSessionFactory的openSession()方法创建Session(实际是DefaultSession)
2.1、 DefaultSession -> Session(策略模式)
//配置文件初始化的Configuration对象
private final Configuration configuration;
//底层依赖的Executor
private final Executor executor;
//是否自动提交事务
private final boolean autoCommit;
//当前缓存中是否有脏数据?
private boolean dirty;
//游标对象记录,close统一关闭
private List<Cursor<?>> cursorList;
- Exectuor包含对数据库的所有操作,根据不同的exectuor来选择不同Executor进行操作
- select 相关:通过executor.query(…)方法来实现数据库查询操作
- update/insert/delete相关:通过executor.update(…)方法来实现数据库的更新或插入操作
- commit\rollback\close相关:分别丢应executor中的相应 的方法来实现
private boolean dirty
这个字段会在update/insert/delete相关
中设置为true,后续将在isCommitOrRollbackRequired
方法中使用,来判断是否提交\回滚事务
2.2、DefaultSqlSessionFactory -> SqlSessionFactory(工厂方法模式)
//八个重载方法,用于创建不同条件下的SqlSession
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
- 内部具体逻辑实现方法为
openSessionFromDataSource(...)
,有两种模式:- 通过数据源连接数据库连接,并创建Executor对象和DefaultSession
- 通过用户提供的Connection,创建Executor对象和DefaultSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//获取config配置文件中配置的Environment对象
final Environment environment = configuration.getEnvironment();
//获取TransactionFactory对象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//创建Transaction对象
tx =
transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//根据配置创建Executor
final Executor executor = configuration.newExecutor(tx, execType);
//创建DefaultSqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
2.3、SqlSessionManager(同线程同Session,ThreadLocal)TODO
3、XMLConfigBuilder -> BaseBuilder(建造者模式)
上述将了如何创建SqlSession并使用,其中贯彻整个SqlSession生命周期的”超级大对象“Configuration初始化流程
3.1、BaseBuilder
- BaseBuilder包含三个核心字段
- Configuration:Mybatis初始化过程中的核心对象,其中包含了几乎全部配置信息且全局唯一的”All-In-One“对象。
- TypeAliasRegistry:Mybatis配置文件中的用标签来定义别名,这些定义会记录在TypeAliasRegistry对象中。
- TypeHandlerRegistry:Mybatis配置文件中的用标签添加自定义的TypeHandler,用于指定数据库字段类型与Java类型之间的转换。
- 其中TypeAliasRegistry和TypeHandlerRegistry对象会在Configuration对象初始化的时候就创建。
- 提供的方法主要有:通过TypeAlias解析对应的类型;获取指定的TypeHandler等等
3.2、 XMLConfigBuilder(主角)
SqlSessionFactoryBuilder中build(…)会构建XMLConfigBuilder对象。
XMLConfigBuilder中的入口:Configuration parse()
- parseConfiguration(parser.evalNode("/configuration"))
- propertiesElement(root.evalNode(“properties”)):解析<properties>节点
- settingsAsProperties(root.evalNode(“settings”)):解析<settings>节点
- typeAliasesElement(root.evalNode(“typeAliases”)):解析<typeAliases>节点
- pluginElement(root.evalNode(“plugins”)):解析<plugins>节点
- objectFactoryElement(root.evalNode(“objectFactory”)):解析<objectFactory>节点
- objectWrapperFactoryElement(root.evalNode(“objectWrapperFactory”)): 解析<objectWrapperFactory>节点
- reflectorFactoryElement(root.evalNode(“reflectorFactory”)):解析<reflectorFactory>节点
- environmentsElement(root.evalNode(“environments”)):解析<environments>节点
- typeHandlerElement(root.evalNode(“typeHandlers”)):解析 <typeHandlers>节点
- mapperElement(root.evalNode(“mappers”)):解析<mappers>节点
3.2.1、propertiesElement:<properties>节点
<properties resource="org/apache/ibatis/databases/blog/blog-derby.properties">
<property name="username" value="root"/>
</properties>
- 解析属性配置,从配置的路径文件resource中按照“=”或者“:”解析key-value,生成Properties对象,为后续使用占位符的地方进行赋值替换。
- 将最终解析的对象设置到Configuration中:
configuration.setVariables(defaults)
3.2.2、settingsAsProperties:<settings>节点
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="false"/>
<setting name="multipleResultSetsEnabled" value="true"/>
.....
</settings>
- Mybatis全局配置,控制其运行时的行为
- 同样是将属性解析为key-value的形式,解析成一个Properties对象,然后记录到Configuration的每个配置的属性中。
3.2.3、typeAliasesElement: <typeAliases>节点
<typeAliases>
<typeAlias alias="Author" type="org.apache.ibatis.domain.blog.Author"/>
<typeAlias type="org.apache.ibatis.domain.blog.Author"/>
</typeAliases>
- 若<typeAliases>节点中配置的是<package>节点,则会扫描指定包下的类,并解析Alias注解,最后完成别名的注册。(要么全是package,要么全是typeAlias)
- 为配置alias时,则会以类的全路径名作为alias,若类被Alias注解,则会取Alias的value作为alias。
- 其他情况,直接调用typeAliasRegistry.registerAlias(alias, clazz);保存到BaseMapper中的typeAliasRegistry属性中,即保存到Configuration的typeAliasRegistry中。
3.2.4、typeHandlerElement: <typeHandler>节点
- 解析逻辑和typeAliasesElement类型,最后会将数据保存到Configuration中的typeHandlerRegistry中。
3.2.5、environmentsElement:<environments>节点
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
- 针对不同的环境,配置不同,之后创建对应的TransactionFactory和DataSource对象。
- 创建TransactionFactory,具体实现是先通过TypeAliasRegistry解析别名之后,实例化TransactionFactory。(Mybatis提供的TransactionFactory实现类已经在构建Configuration时初始化好了,也可以自定义)
- 创建DataSourceFactory,处理逻辑和TransactionFactory类似,并获取对应的DataSource。
- 创建Environment对象,保存到Configuration中。
3.2.6、pluginElement:<plugins>节点
- TODO
3.3、mapperElement:Mapper映射文件解析
见Mapper映射文件解析篇
3.4、bindMapperForNamespace():Mapper接口绑定
通过命名空间绑定 mapper 接口,这样才能将映射文件中的 SQL 语句和 mapper 接口中的方法绑定在一起(记录在Configuration的MapperRegistry mapperRegistry
),后续即可通过调用 mapper 接口方法执行与之对应的 SQL 语句。
3.5、解析未完成的节点
- parsePendingResultMaps()
- ResultMapResolver:解析未完成的
resultMap
节点
- ResultMapResolver:解析未完成的
- parsePendingCacheRefs()
- CacheRefResolver:解析未完成的
cacheRef
节点
- CacheRefResolver:解析未完成的
- parsePendingStatements()
- XMLStatementBuilder:重新解析
4、完成解析
- 完成各种文件的解析,所有的数据配置都存放在Configuration整个超级大对象中,最后再构建默认的SqlSessionFactory,
new DefaultSqlSessionFactory(config)
- 后续SQL执行的主要工具入口就是
DefaultSqlSessionFactory
,会用其来创建SqlSession
并执行SQL。
上述内容仅为Config配置文件源码阅读思路的主线,后续文章会对其中各核心类进行单独的解析~