MyBatis源码通~Config配置文件解析主线

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(...),有两种模式:
    1. 通过数据源连接数据库连接,并创建Executor对象和DefaultSession
    2. 通过用户提供的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节点
  • parsePendingCacheRefs()
    • CacheRefResolver:解析未完成的cacheRef节点
  • parsePendingStatements()
    • XMLStatementBuilder:重新解析

4、完成解析

  • 完成各种文件的解析,所有的数据配置都存放在Configuration整个超级大对象中,最后再构建默认的SqlSessionFactory,new DefaultSqlSessionFactory(config)
  • 后续SQL执行的主要工具入口就是DefaultSqlSessionFactory,会用其来创建SqlSession并执行SQL。

上述内容仅为Config配置文件源码阅读思路的主线,后续文章会对其中各核心类进行单独的解析~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只打杂的码农

你的鼓励是对我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值