MyBatis源码解析(三):初始化SqlSession

       前言:在MyBatis源码解析(二):初始化SqlSessionFactory中,已经成功解析XML配置文件,并初始化SqlSessionFactory;这一篇将对 SqlSessionFactory.openSession() 进行解析

一,SqlSessionFactory.openSession() 执行流程

二,初始化步骤

    1,触发 openSession(),内部调用 openSessionFromDataSource() 完成初始化动作

public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 从Configuration中获取Environment配置信息
      final Environment environment = configuration.getEnvironment();
      // 从Environment配置信息获取事务工厂
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 初始化事务, 此时事务持有dataSource对象
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 初始化Executor, Executor通过Transaction间接持有DataSource对象
      final Executor executor = configuration.newExecutor(tx, execType);
      // 初始化SqlSession对象, SqlSession持有configuration和executor引用
      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();
    }
  }

    2,初始化数据库事务 -- JdbcTransactionFactory.newTransaction

public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    // 此时数据库事务持有DataSource信息
    return new JdbcTransaction(ds, level, autoCommit);
  }

    3,初始化 Executor 执行对象 -- Configuration.newExecutor

        * ExecuteType配置信息和CacheEnabled配置信息官网解释

        * 初始化Executor方法;在开启缓存处理的情况下,注意此处通过装饰者模式对 SimpleExecutor 进行了二次装饰 CachingExecutor

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    // executorType如果未配置, 默认为Simple
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    // 未配置默认开启
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    // 通过拦截器加载plugin, 返回对象为代理对象
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

        * Executor 初始化时, 关联加载 Plugin 插件,并生成Executor代理对象,此处注意:代理对象可以被再次代理

public Object pluginAll(Object target) {
    // 此处遍历Plugins标签内所有Plugin进行加载
    // 通过代理对象再代理模式, 保证每一个拦截器都能被执行
    // 此处注意点 : 代理对象可以被再次代理
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

        * 生成 Executor 对象的代理对象,如存在多个,则后续传入的对象已经是代理对象,类似装饰者模式方式

public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    // 存在有效插件
    if (interfaces.length > 0) {
      // 对target即executor进行代理
      // 外部循环调用, 则此时executor对象可能已经是代理对象
      // 允许对代理对象再次进行代理
      // 最终执行时, 装箱代理, 拆箱调用, 类似装饰者模式一层层进行处理
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

    4,初始化SqlSession成功,获取的 SqlSession 为 DefaultSqlSession,此时 SqlSession 持有配置对象 Configuration,执行对象 CachingExecetor,已经持有 DataSource 配置的数据库事务对象 Transaction

SqlSession sqlSession = sqlSessionFactory.openSession();

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值