• [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(...)

  • 相关阅读:
    centos 卸载自带的apache
    静态方法绑定
    安装apc
    避免SSH连接因超时闲置断开
    svn使用安全问题
    接口类,和抽象类。
    function (规定参数必须为某个对象的实例)
    jquery 获取DIV边框的宽
    正则表达式(非捕获)
    Linux ftp服务器Proftp配置
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/13696951.html
Copyright © 2020-2023  润新知