[Re] MyBatis-3(源码流程)

HelloWorld 源码全流程

SqlSessionFactory 的初始化

SqlSessionFactoryBuilder

public SqlSessionFactory build(InputStream inputStream
        , String environment, Properties properties) {
    try {
      // 创建解析器
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      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.
      }
    }
}

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

XMLConfigBuilder

public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    parseConfiguration(parser.evalNode("/configuration")); // 根节点
    return configuration;
}

private void parseConfiguration(XNode root) {
    // 挨个解析<configuration>下的每一个子节点,将详细信息保存在 configuration 中
    try {
      Properties settings = settingsAsPropertiess(root.evalNode("settings"));
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

// props ←→ <settings>
private void settingsElement(Properties props) throws Exception {
    configuration.setAutoMappingBehavior(AutoMappingBehavior
            .valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
    configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior
            .valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
    configuration.setCacheEnabled(
            booleanValueOf(props.getProperty("cacheEnabled"), true));
    configuration.setProxyFactory(
            (ProxyFactory) createInstance(props.getProperty("proxyFactory")));
    configuration.setLazyLoadingEnabled(booleanValueOf(
            props.getProperty("lazyLoadingEnabled"), false));
    configuration.setAggressiveLazyLoading(
            booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
    configuration.setMultipleResultSetsEnabled(
            booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
    configuration.setUseColumnLabel(
            booleanValueOf(props.getProperty("useColumnLabel"), true));
    configuration.setUseGeneratedKeys(
            booleanValueOf(props.getProperty("useGeneratedKeys"), false));
    configuration.setDefaultExecutorType(
            ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
    configuration.setDefaultStatementTimeout(
            integerValueOf(props.getProperty("defaultStatementTimeout"), null));
    configuration.setDefaultFetchSize(
            integerValueOf(props.getProperty("defaultFetchSize"), null));
    configuration.setMapUnderscoreToCamelCase(
            booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
    configuration.setSafeRowBoundsEnabled(
            booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
    configuration.setLocalCacheScope(
            LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
    configuration.setJdbcTypeForNull(
            JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
    configuration.setLazyLoadTriggerMethods(stringSetValueOf(
            props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
    configuration.setSafeResultHandlerEnabled(
            booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
    configuration.setDefaultScriptingLanguage(
            resolveClass(props.getProperty("defaultScriptingLanguage")));
    configuration.setCallSettersOnNulls(
            booleanValueOf(props.getProperty("callSettersOnNulls"), false));
    configuration.setUseActualParamName(
            booleanValueOf(props.getProperty("useActualParamName"), false));
    configuration.setLogPrefix(props.getProperty("logPrefix"));
    @SuppressWarnings("unchecked")
    Class<? extends Log> logImpl =
            (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
    configuration.setLogImpl(logImpl);
    configuration.setConfigurationFactory(
            resolveClass(props.getProperty("configurationFactory")));
}

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(
                    inputStream, configuration, resource, configuration.getSqlFragments());
            // ===== ↓↓↓ Step Into ↓↓↓ =====> #1.3
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(
                    inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url"
                    + ", resource or class, but not more than one.");
          }
        }
      }
    }
}

XMLMapperBuilder

private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      cacheRefElement(context.evalNode("cache-ref"));
      cacheElement(context.evalNode("cache"));
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      // 可重用 SQL
      sqlElement(context.evalNodes("/mapper/sql"));
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
}

private void buildStatementFromContext(List<XNode> list) {
    if (configuration.getDatabaseId() != null) {
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    buildStatementFromContext(list, null);
}

private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    for (XNode context : list) {
      // 解析 CRUD 标签的解析器
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(
              configuration, builderAssistant, context, requiredDatabaseId);
      try {
        // ===== ↓↓↓ Step Into ↓↓↓ =====> #1.4
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
}

XMLStatementBuilder

public void parseStatementNode() {

    // 将 CRUD 标签中的一个个属性都解析出来 ...

    // ===== ↓↓↓ Step Into ↓↓↓ =====
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType
        , fetchSize, timeout, parameterMap, parameterTypeClass, resultMap
        , resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered
        , keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}

MapperBuilderAssistant

public MappedStatement addMappedStatement(对应上一步的那一堆配置...) {
    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(
            configuration, id, sqlSource, sqlCommandType).配置全部加进来;

    ParameterMap statementParameterMap =
            getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }

    // 根据解析出来的配置,构建一个 MappedStatement 对象(封装一个 CRUD 标签的详细信息)
    MappedStatement statement = statementBuilder.build();
    // 把这个 MappedStatement 加入到 configuration 中
    configuration.addMappedStatement(statement);
    return statement;
}

Configuration

Configuration 对象保存了所有配置文件(全局、映射) 的详细信息。

获取 SqlSession

Mybatis 四大组件之一的 Executor 在这一步会被创建。

DefaultSqlSessionFactory

@Override
public SqlSession openSession(boolean autoCommit) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    return openSessionFromDataSource(
            configuration.getDefaultExecutorType(), null, autoCommit);
}

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);
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 得先创建 Executor → #2.2
      final Executor executor = configuration.newExecutor(tx, execType);
      // Executor 作为 SqlSession 构造器形参之一,只有先有它才能创建 SqlSession → #2.5
      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();
    }
}

Configuration

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    // 根据 Executor 在全局配置文件中配置的类型,创建出相应的 XxxExecutor
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else { // SIMPLE
      executor = new SimpleExecutor(this, transaction); // √
    }
    if (cacheEnabled) {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 若配置了二级缓存 → #2.3
      executor = new CachingExecutor(executor); // 包装 Executor
    }
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 返回经拦截器们包装后的 Executor → #2.4
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

CachingExecutor

public class CachingExecutor implements Executor {

  // 原始 Executor
  private Executor delegate;
  // 二级缓存
  private TransactionalCacheManager tcm = new TransactionalCacheManager();

  // 对传进来的 Executor 做了包装,并返回包装后的 Executor
  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;
    delegate.setExecutorWrapper(this);
  }

  // ...
}

InterceptorChain

private final List<Interceptor> interceptors = new ArrayList<Interceptor>();

public Object pluginAll(Object target) {
    // 每个拦截器都来重新包装 Executor
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
}

DefaultSqlSession

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
}

返回 Mapper 代理对象

DefaultSqlSession

@Override
public <T> T getMapper(Class<T> type) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    return configuration.<T>getMapper(type, this);
}

Configuration

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    return mapperRegistry.getMapper(type, sqlSession);
}

MapperRegistry

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 根据 Mapper<I> 类型从这个 Map 中拿到对应的 MapperProxyFactory
    final MapperProxyFactory<T> mapperProxyFactory
            = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> mapperProxyFactory 根据 sqlSession 创建 MapperProxy
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

MapperProxyFactory

public T newInstance(SqlSession sqlSession) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #3.5 → 创建 MapperProxy 对象
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(
                                sqlSession, mapperInterface, methodCache);
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 对上一步创建的 MapperProxy 对象做动态代理,并返回
    return newInstance(mapperProxy);
}

@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader()
            , new Class[] { mapperInterface }, mapperProxy);
}

MapperProxy

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession
          , Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

}

调用查询方法

MapperProxy

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 传入 sqlSession 和方法参数
    return mapperMethod.execute(sqlSession, args);
}

MapperMethod

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
    	Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          // ===== ↓↓↓ Step Into ↓↓↓ =====> 封装参数 → 下面的方法
          Object param = method.convertArgsToSqlCommandParam(args);
          // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.4
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type ("
          + method.getReturnType() + ").");
    }
    return result;
}

public static class MethodSignature {
    private final ParamNameResolver paramNameResolver;

    public Object convertArgsToSqlCommandParam(Object[] args) {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 调用参数解析器 → #4.3
      return paramNameResolver.getNamedParams(args);
    }
}

ParamNameResolver

private static final String GENERIC_NAME_PREFIX = "param";

public ParamNameResolver(Configuration config, Method method) {
    final Class<?>[] paramTypes = method.getParameterTypes();
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();
    final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
    int paramCount = paramAnnotations.length;
    // get names from @Param annotations
    for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
      if (isSpecialParameter(paramTypes[paramIndex])) {
        // skip special parameters
        continue;
      }
      String name = null;
      for (Annotation annotation : paramAnnotations[paramIndex]) {
        if (annotation instanceof Param) {
          hasParamAnnotation = true;
          name = ((Param) annotation).value();
          break;
        }
      }
      if (name == null) {
        // @Param was not specified.
        if (config.isUseActualParamName()) {
          name = getActualParamName(method, paramIndex);
        }
        if (name == null) {
          // use the parameter index as the name ("0", "1", ...)
          // gcode issue #71
          name = String.valueOf(map.size());
        }
      }
      map.put(paramIndex, name);
    }
    names = Collections.unmodifiableSortedMap(map);
}

public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    if (args == null || paramCount == 0) {
      return null;
    } else if (!hasParamAnnotation && paramCount == 1) {
      return args[names.firstKey()];
    } else {
      final Map<String, Object> param = new ParamMap<Object>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
}

DefaultSqlSession

@Override
public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    List<T> list = this.<T>selectList(statement, parameter);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be"
              + "returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
}

@Override
public <E> List<E> selectList(String statement, Object parameter) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    // statement: cn.edu.nuist.mapper.TeacherMapper.getTeacherByTid
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      // Configuration 成员:Map<String, MappedStatement> mappedStatements
      // 根据该 statement(select标签的唯一标识),拿到了对应的 MappedStatement
      // 该 MappedStatement 对象中封装了对应的 <select> 的详细信息
      MappedStatement ms = configuration.getMappedStatement(statement);
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 先钻入下面的方法 → 然后是 #4.5
      return executor.query(
              ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
}

// 嘿!
private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("collection", object);
      if (object instanceof List) {
        map.put("list", object);
      }
      return map;
    } else if (object != null && object.getClass().isArray()) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("array", object);
      return map;
    }
    return object;
}

CachingExecutor

@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject
        , RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject
        , RowBounds rowBounds, ResultHandler resultHandler
        , CacheKey key, BoundSql boundSql) throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        // 先看二级缓存(TransactionalCacheManager) 中有没有
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.6
          list = delegate.<E> query(
                  ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

CachingExecutor 是对 Executor 的包装,所以最终还是调用原始 Executor 的 query 方法。

BaseExecutor

@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter
        , RowBounds rowBounds, ResultHandler resultHandler, CacheKey key
        , BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource())
            .activity("executing a query").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      queryStack++;
      // 拿 cacheKey 在一级缓存(localCache) 中查找!
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else { // 没找到就去 DB 中找
        // ===== ↓↓↓ Step Into ↓↓↓ =====
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
}

private <E> List<E> queryFromDatabase(MappedStatement ms
        , Object parameter, RowBounds rowBounds, ResultHandler resultHandler
        , CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 4.7
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    // 放在本地缓存中
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
}

SimpleExecutor*

在此方法内创建了 StatementHandler (ParameterHandler、ResultSetHandler)

@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter
        , RowBounds rowBounds, ResultHandler resultHandler
        , BoundSql boundSql) throws SQLException {

    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      // ===== ↓↓↓ Step Into ↓↓↓ =====> StatementHandler(可用来创建 Statement 对象) → #4.8
      StatementHandler handler = configuration.newStatementHandler(
              wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 创建 Statement 对象 → 就在下面 ~
      stmt = prepareStatement(handler, ms.getStatementLog());
      // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.9[3]
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
}

private Statement prepareStatement(
        StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.11
    // 面上是 StatementHandler 调用的,实际是 ParameterHandler 来做的参数预编译
    // ParameterHandler 创建时机:创建 StatementHandler 时一并创建的 → #4.10
    handler.parameterize(stmt);
    return stmt;
}

Configuration

public StatementHandler newStatementHandler(Executor executor
        , MappedStatement mappedStatement, Object parameterObject
        , RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.9
    StatementHandler statementHandler = new RoutingStatementHandler(executor
            , mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    // 使用拦截器包装 StatementHandler
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}

public ParameterHandler newParameterHandler(
        MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang()
            .createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
}

public ResultSetHandler newResultSetHandler(Executor executor
        , MappedStatement mappedStatement, RowBounds rowBounds
        , ParameterHandler parameterHandler, ResultHandler
        resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor,
            mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
}

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    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);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

RoutingStatementHandler

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter
        , RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor
                , ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        // ===== ↓↓↓ Step Into ↓↓↓ =====> { super(...); } → #4.10
        delegate = new PreparedStatementHandler(executor
                , ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor
                , ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }
}

@Override
public void parameterize(Statement statement) throws SQLException {
    delegate.parameterize(statement);
}

@Override
public <E> List<E> query(Statement statement
        , ResultHandler resultHandler) throws SQLException {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.11[2]
    return delegate.<E>query(statement, resultHandler);
}

BaseStatementHandler

protected BaseStatementHandler(Executor executor, MappedStatement
        mappedStatement, Object parameterObject, RowBounds rowBounds,
        ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 还会同时创建另外两个组件!!! → 组件创建: #4.8
    this.parameterHandler = configuration.newParameterHandler(
            mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor
            , mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

如果看到这了,现在再回到 #4.7!看第二个要 Step Into 的地方!

PreparedStatementHandler

@Override
public void parameterize(Statement statement) throws SQLException {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.12
    parameterHandler.setParameters((PreparedStatement) statement);
}

@Override
public <E> List<E> query(Statement statement
        , ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.13
    return resultSetHandler.<E> handleResultSets(ps);
}

DefaultParameterHandler

@Override
public void setParameters(PreparedStatement ps) {
    // ...

    // TypeHandler 给 SQL 预编译设置参数
    TypeHandler typeHandler = parameterMapping.getTypeHandler();
    JdbcType jdbcType = parameterMapping.getJdbcType();
    if (value == null && jdbcType == null) {
        jdbcType = configuration.getJdbcTypeForNull();
    }
    typeHandler.setParameter(ps, i + 1, value, jdbcType);

    // ...
}

回到 #4.7,继续走第 3 个断点。

DefaultResultSetHandler

JavaBean 和表记录的映射(设置参数、结果映射) 由 TypeHandler 完成。

private Object getPropertyMappingValue(ResultSet rs
        , MetaObject metaResultObject, ResultMapping propertyMapping
        , ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    if (propertyMapping.getNestedQueryId() != null) {
      return getNestedQueryMappingValue(rs
              , metaResultObject, propertyMapping, lazyLoader, columnPrefix);
    } else if (propertyMapping.getResultSet() != null) {
      addPendingChildRelation(rs, metaResultObject, propertyMapping);
      return DEFERED;
    } else {
      final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      return typeHandler.getResult(rs, column);
    }
}

小结

总结

  • 根据配置文件(全局、映射) 初始化出 Configuration 对象
  • 创建一个 DefaultSqlSession 对象,其中包含 Configuration、Executor (根据全局配置文件中的 defaultExecutorType 创建出对应的 Executor) 对象的引用。
  • DefaultSqlSession.getMapper(class),首先拿到 Mapper<I> 对应的 MapperProxyFactory,然后通过 newInstance() 创建 MapperProxy 对象,最终返回的是该对象的动态代理。
  • 执行 CRUD 方法
    • 底层是代理对象调用了 DefaultSqlSession 对象的 CRUD 方法
    • 会创建一个 Statement 对象 (会首先创建 StatementHandler,而在 StatementHandler 的构造器中又会创建 ParameterHandler、ResultSetHandler 对象)
    • 调用 StatementHandler 预编译参数以及设置参数值(底层实际是调用 ParameterHandler 来做的)
    • 调用 StatementHandler 的 CRUD 方法
    • 使用 ResultSetHandler 封装结果

【注意】MyBatis 的四大组件创建过程中,都有插件进行介入:interceptorChain.pluginAll(...)

原文地址:https://www.cnblogs.com/liujiaqi1101/p/13696951.html