mybatis源码解析

一:配置(约定大于配置)

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)

二. 源码分析

2.1 从调用方法build 对源码理解

step1 : 进入build

mybatis源码解析_第1张图片

step2: 再进入build

mybatis源码解析_第2张图片

step3: 看到SqlSessionFactory

mybatis源码解析_第3张图片

 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
    // 1.SqlSessionFactory传递了一个InputStream,这个InputStream把带有的文件信息,传递给XMLConfigBuilder的对象parser
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
  
  
  1.SqlSessionFactory传递了一个InputStream,这个InputStream把带有的文件信息,传递给XMLConfigBuilder的对象parser
  2.parser调用了parse()方法,来解析xml	

step4 进入parse()方法

mybatis源码解析_第4张图片

 public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // configuration是xml的跟节点,即在parseConfiguration这个方法中去解析xml
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
  
  1.configuration是xml的跟节点
  2.parse() 方法利用parseConfiguration这个方法去解析xml

step 5 进入 parseConfiguration

mybatis源码解析_第5张图片

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
  
  1.根据我们一开始提到的配置顺序来看,可以这个parseConfiguration方法把xml从头到尾的每个节点都拿过来进行解析
  2.具体通过
   propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      来解析整个xml

2.2 从返回对象SqlSessionFactory 对源码进行理解

2.2.1 进入 SqlSessionFactory

mybatis源码解析_第6张图片


  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();
  
  
  1.进入SqlSessionFactory 这个方法中,看到了一堆的SqlSession,由于SqlSession是接口所以我们要去找他的接口实现类去看源码

2.2.2 找SqlSessionFactory的接口实现类DefaultSqlSessionFactory

mybatis源码解析_第7张图片

mybatis源码解析_第8张图片

在这里插入图片描述

mybatis源码解析_第9张图片

mybatis源码解析_第10张图片

1.找到了SqlSessionFactory的接口实现类 DefaultSqlSessionFactory
2.于是我们再返回SqlSessionFactoryBuilder中去查找他SqlSessionFactory的接口实现类DefaultSqlSessionFactory,并且进入其中查看源码
3.通过SqlSessionFactoryBuilder用于返回SqlSessionFactory对象的方法,进入其中找到下面一段代码
  
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
  
  
  1.可见其返回的SqlSessionFactory中,new了DefaultSqlSessionFactory这个对象
  2.且new 出来的这个DefaultSqlSessionFactory对象里面带有 Configuration 解析的xml文件的内容config,也就是给new出来的DefaultSqlSessionFactory里传了带有xml内容的config。
   也就是new DefaultSqlSessionFactory(config);的含义

2.2.3 进入DefaultSqlSessionFactory看他是怎么返回带解析了的xml内容的config

mybatis源码解析_第11张图片

2.2.3.1 进入DefaultSqlSessionFactory之前我们要先看一下 ,我们要获得什么内容

mybatis源码解析_第12张图片

1.由于SqlSession是向数据库去发送指令的
2.明确得到什么,得到的数据用来做什么之后我们再进入DefaultSqlSessionFactory

2.2.3.2 进入DefaultSqlSessionFactory

mybatis源码解析_第13张图片

1.由于我们是为了去得到session对象,所以我们进入openSessionFromDataSource这个方法去看他怎么去得到我们的session对象
2.因为这个方法的返回参数类型是SqlSession,所以我们返回的一定是session对象,于是我们决定进入这个代码

2.2.3.3 进入openSessionFromDataSource方法看他怎么返回session对象

mybatis源码解析_第14张图片

  @Override
  public Configuration getConfiguration() {
    return configuration;
  }

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
   
   //事务
   Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      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); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
  
  
  
  1.第一步先查看最终返回值DefaultSqlSession,其中有configuration, executor, autoCommit,根据前面的解释大体知道第一个是xml的什么东西,但是不确定后面的,继续看
  2.第二步看到Executor,这个我们知道是解析器,但是不确定这个方法做了什么,返回了什么,所以我们选择进入这个方法

2.2.3.3 进入Executor这个方法,我们查看这个方法做了什么,解析了什么

mybatis源码解析_第15张图片

public interface Executor {

  ResultHandler NO_RESULT_HANDLER = null;

  int update(MappedStatement ms, Object parameter) throws SQLException;

   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

   Cursor queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;

  List flushStatements() throws SQLException;

//提交事务
  void commit(boolean required) throws SQLException;

//回滚
  void rollback(boolean required) throws SQLException;

  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

  boolean isCached(MappedStatement ms, CacheKey key);

  void clearLocalCache();

  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class targetType);

  Transaction getTransaction();

  void close(boolean forceRollback);

  boolean isClosed();

  void setExecutorWrapper(Executor executor);

}
1.进入Executor这个方法我们发现,这个Executor也是一个接口
2.这个Executor接口提供了,增删改查最基础的方法
3.提交事务
4.回滚事务
5.由于Executor是一个接口,所以我们继续来查找这个Executor接口的实现类

2.2.3.4 查找Executor接口的实现类

mybatis源码解析_第16张图片

1.由于Executor接口的实现类的实现类太多,在这里我们就去看一下他这个简单接口实现类,直接ctrl+n,去看这个实现类SimpleExecutor的源码
2.找到后发现他这里执行两个方法

mybatis源码解析_第17张图片

方法1:douptate

mybatis源码解析_第18张图片

1.发现Statement对象,顿时明白了mybatis底层也是用jdbc来操作数据库的

方法二:doQuery 对象

mybatis源码解析_第19张图片

1.又发现了利用statement对象去返回数据库,确定了mybatis底层肯定是用jdbc去操作数据库的

你可能感兴趣的:(mybatis,mybatis)