mybatis源码分析-资源加载-下篇

处理mapper节点

构造函数中已经有很多很多默认类型匹配。这就是为什么在写sql的时候返回类型会自动映射到相应的java类型上面,这里已经处理好了。继续看最复杂的mapper在上面处理configuration节点的最后一句mapperElement(root.evalNode("mappers"));。这个是配置文件里面最复杂的,所以再处理上面Mybatis多写了两个类专门处理mapper数据XMLMapperBuilderXMLStatementBuilder

  • XMLMapperBuilder 处理mapper文件里面的resultMap,parameterMap,sql,cache等数据的解析
  • XMLStatementBuilder 处理这四类sql语句的处理

先来看看XMLMapperBuilder解析mapper表层文件

private void configurationElement(XNode context) {
    try {
        //拿到namespace。也就是类名
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      //将当前namespace设置为当前builderAssistant的命名空间
      builderAssistant.setCurrentNamespace(namespace);
      //处理cache-ref
      cacheRefElement(context.evalNode("cache-ref"));
      //处理cache
      cacheElement(context.evalNode("cache"));
        /**
         * 注册参数map
         * 
         * 
         * 
         */
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
        /**
         * 最终将resultMap转换成ResultMap对象。并将ResultMap对象放到configuration对象里面
         * 
         * 
         * 
         * 
         */
      resultMapElements(context.evalNodes("/mapper/resultMap"));

      //我们可以使用通用的sql注入到别的sql里面,这些sql放到sqlFragments这个map里面。这步比较简单
      sqlElement(context.evalNodes("/mapper/sql"));

      //处理sql  sql语句比较复杂,所以使用单独的类XMLStatementBuilder类来出来
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
  }

如果你已经按照前面分析配置文件的过程一路走了一遍,那么处理parameterMap和resultMap就很简单了,就是那个节点内容区出里面的各种属性,最终注册到对应的类上面。注册parameterMap使用类ParameterMap和ParameterMapping细节就不一一描述了。再看一下resultMap

    private ResultMap resultMapElement(XNode resultMapNode, List additionalResultMappings) throws Exception {
        ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
        // 获得id
        String id = resultMapNode.getStringAttribute("id",
                resultMapNode.getValueBasedIdentifier());
        // 获得type
        String type = resultMapNode.getStringAttribute("type",
                resultMapNode.getStringAttribute("ofType",
                        resultMapNode.getStringAttribute("resultType",
                                resultMapNode.getStringAttribute("javaType"))));
        // 一般没有设置,为空
        String extend = resultMapNode.getStringAttribute("extends");
        // 一般没有设置,为空
        Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
        //这里首先去typeAlias中看有没有别名,没有才回通过反射生成class对象
        Class typeClass = resolveClass(type);
        Discriminator discriminator = null;
        List resultMappings = new ArrayList();
        // 第一次additionalResultMappings为空
        resultMappings.addAll(additionalResultMappings);
        //节点下的节点。 
        List resultChildren = resultMapNode.getChildren();
        //遍历results下面所有的result节点
        for (XNode resultChild : resultChildren) {
            if ("constructor".equals(resultChild.getName())) {
                processConstructorElement(resultChild, typeClass, resultMappings);
            } else if ("discriminator".equals(resultChild.getName())) {
                discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
            } else {
                List flags = new ArrayList();
                if ("id".equals(resultChild.getName())) {
                    flags.add(ResultFlag.ID);
                }
                //最普通的column和property就在这里处理
                resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
            }
        }
        ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
        try {
            return resultMapResolver.resolve();
        } catch (IncompleteElementException e) {
            configuration.addIncompleteResultMap(resultMapResolver);
            throw e;
        }
    }

处理resultMap节点将每一个result子节点封装成ResultMapping对象。然后将resultMapping对象和赋值给MapperBuilderAssistant。下面重点分析select,insert等标签处理的

    private void buildStatementFromContext(List list, String requiredDatabaseId) {
        for (XNode context : list) {
            final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
            try {
                statementParser.parseStatementNode();
            } catch (IncompleteElementException e) {
                configuration.addIncompleteStatement(statementParser);
            }
        }
    }

因为sql处理比较复杂,所以单独创建XMLStatementBuilder来处理sql。上面方法中使用for循环list表示多个sql语句会使用多个XMLStatementBuilder来创建每个sql语句。

    public void parseStatementNode() {
        String id = context.getStringAttribute("id");
        String databaseId = context.getStringAttribute("databaseId");

        if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
            return;
        }

        Integer fetchSize = context.getIntAttribute("fetchSize");
        Integer timeout = context.getIntAttribute("timeout");
        String parameterMap = context.getStringAttribute("parameterMap");
        String parameterType = context.getStringAttribute("parameterType");
        //从TypeAliasRegistry里面获得对象,如果不是别名,则通过classUtil创建一个class对象
        Class parameterTypeClass = resolveClass(parameterType);
        String resultMap = context.getStringAttribute("resultMap");
        String resultType = context.getStringAttribute("resultType");
        String lang = context.getStringAttribute("lang");
        LanguageDriver langDriver = getLanguageDriver(lang);

        Class resultTypeClass = resolveClass(resultType);
        String resultSetType = context.getStringAttribute("resultSetType");
        StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
        ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);

        String nodeName = context.getNode().getNodeName();
        SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
        boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
        boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
        boolean useCache = context.getBooleanAttribute("useCache", isSelect);
        boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

        // Include Fragments before parsing
        XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
        includeParser.applyIncludes(context.getNode());

        // Parse selectKey after includes and remove them.
        processSelectKeyNodes(id, parameterTypeClass, langDriver);

        // Parse the SQL (pre:  and  were parsed and removed)
        //这个是sql语句处理的地方,最终将sql语句包装成了BoundSql对象。
        /**
         * 对象中包含下面属性
         *   private String sql;  sql语句
         *   private List parameterMappings;  参数map
         *   private Object parameterObject;
         *   private Map additionalParameters;
         *   private MetaObject metaParameters;
         */
        SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
        String resultSets = context.getStringAttribute("resultSets");
        String keyProperty = context.getStringAttribute("keyProperty");
        String keyColumn = context.getStringAttribute("keyColumn");
        KeyGenerator keyGenerator;
        String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
        keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
        if (configuration.hasKeyGenerator(keyStatementId)) {
            keyGenerator = configuration.getKeyGenerator(keyStatementId);
        } else {
            keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
                    configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
                    ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
        }

        //上面将