3.3 mybatis源码篇-XMLMapperBuilder

版本说明:mybatis3.4.0

一、我们关注mapper的解析

解析的内容太多了,大家可以自己去查看源码、在这里我们关注mapper的解析、mapper解析成多个MappedStatement

上面章提到的XMLConfigBuilder里面:

this.mapperElement(root.evalNode("mappers"));
private void mapperElement(XNode parent) throws Exception {
        if (parent != null) {
            Iterator i$ = parent.getChildren().iterator();

            while(true) {
                while(i$.hasNext()) {
                    XNode child = (XNode)i$.next();
                    String resource;
                    if ("package".equals(child.getName())) {//取出的标签package
                        resource = child.getStringAttribute("name");
                        this.configuration.addMappers(resource);
                    } else {
                        resource = child.getStringAttribute("resource");//取出的标签是resource
                        String url = child.getStringAttribute("url");
                        String mapperClass = child.getStringAttribute("class");
                        XMLMapperBuilder mapperParser;
                        InputStream inputStream;
                        if (resource != null && url == null && mapperClass == null) {
                            ErrorContext.instance().resource(resource);
                            inputStream = Resources.getResourceAsStream(resource);//取出mapepr.xml进行解析
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        } else if (resource == null && url != null && mapperClass == null) {
                            ErrorContext.instance().resource(url);
                            inputStream = Resources.getUrlAsStream(url);
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        } else {
                            if (resource != null || url != null || mapperClass == null) {
                                throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                            }

                            Class<?> mapperInterface = Resources.classForName(mapperClass);
                            this.configuration.addMapper(mapperInterface);
                        }
                    }
                }

                return;
            }
        }
    } 

解析mapper标签,有两种形式,分别是扫描package和mapper标签、只能使用一种方式加载mapper

<mappers>
      <mapper resource="mapper/AbcMapper.xml"/>
</mappers>
<mappers>
       <package name="com.ys.mapper"/>
</mappers> 
2、XMLMapperBuilder解析
   public void parse() {
        if (!this.configuration.isResourceLoaded(this.resource)) {
            this.configurationElement(this.parser.evalNode("/mapper"));//关注mapper.xml的解析、里面解析了MappedStatement
            this.configuration.addLoadedResource(this.resource);
            //这里注册mapper动态代理对象。并且注册注解的方法(@select等)成MappedStatement、详情看下面
            this.bindMapperForNamespace();   
        }

        this.parsePendingResultMaps();
        this.parsePendingChacheRefs();
        this.parsePendingStatements();
    }
    //..
    private void configurationElement(XNode context) {
        try {
            String namespace = context.getStringAttribute("namespace");
            if (namespace != null && !namespace.equals("")) {
                this.builderAssistant.setCurrentNamespace(namespace);
                this.cacheRefElement(context.evalNode("cache-ref"));
                this.cacheElement(context.evalNode("cache"));
                this.parameterMapElement(context.evalNodes("/mapper/parameterMap"));
                this.resultMapElements(context.evalNodes("/mapper/resultMap"));
                this.sqlElement(context.evalNodes("/mapper/sql"));
                this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));//解析执行的sql标签
            } else {
                throw new BuilderException("Mapper's namespace cannot be empty");
            }
        } catch (Exception var3) {
            throw new BuilderException("Error parsing Mapper XML. Cause: " + var3, var3);
        }
    }
    //..
        private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
            Iterator i$ = list.iterator();
    
            while(i$.hasNext()) {
                XNode context = (XNode)i$.next();//可以看到这里有出现了Builder对象、XMLStatementBuilder
                XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration, this.builderAssistant, context, requiredDatabaseId);
    
                try {
                    statementParser.parseStatementNode();
                } catch (IncompleteElementException var7) {
                    this.configuration.addIncompleteStatement(statementParser);
                }
            }
    
        }
    
3、XMLStatementBuilder的解析把上面的(select|insert|update|delete)标签解析成MappedStatement对象、用于执行
    public void parseStatementNode() {
        String id = this.context.getStringAttribute("id");
        String databaseId = this.context.getStringAttribute("databaseId");
        if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
             //....
            SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);//我们关注这个
            //.....
            this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
        }
    } 

SqlSource

/**
 * Represents the content of a mapped statement read from an XML file or an annotation. 
 * It creates the SQL that will be passed to the database out of the input parameter received from the user.
 * 
 * @author Clinton Begin
 */
 // 以上注释就不作翻译了.
public interface SqlSource {

  BoundSql getBoundSql(Object parameterObject);

} 
SqlSource
    StaticSqlSource  //  SqlSource实例的直接构造者就是 SqlSourceBuilder, 而SqlSourceBuilder中的parse方法所返回的是StaticSqlSource实例.
    RawSqlSource  // 
    ProviderSqlSource
    DynamicSqlSource 

一个例子:下面属性储存着执行的sql

public class StaticSqlSource implements SqlSource {
    private String sql;
    private List<ParameterMapping> parameterMappings;
    private Configuration configuration;
    //....
}

4、注册mapper,
private void bindMapperForNamespace() {
        String namespace = this.builderAssistant.getCurrentNamespace();
        if (namespace != null) {
            Class boundType = null;

            try {
                boundType = Resources.classForName(namespace);
            } catch (ClassNotFoundException var4) {
            }

            if (boundType != null && !this.configuration.hasMapper(boundType)) {
                this.configuration.addLoadedResource("namespace:" + namespace);
                this.configuration.addMapper(boundType);
            }
        } 
    }
    } 
public class MapperRegistry {
    //..
        public <T> void addMapper(Class<T> type) {
        //...
                    this.knownMappers.put(type, new MapperProxyFactory(type));
                    MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
                    parser.parse();//解析注解
         //...
        }
    
    //...
} 
public class MapperAnnotationBuilder {
    //...
    public void parse() {
    //..
        for(int i$ = 0; i$ < len$; ++i$) {
            Method method = arr$[i$];

            try {
                if (!method.isBridge()) {
                    this.parseStatement(method);//把方法解析成MappedStatement
                }
            } catch (IncompleteElementException var8) {
                this.configuration.addIncompleteMethod(new MethodResolver(this, method));
            }
        }
         //..
    } 
    //..
} 

我们已经知道如何解析mapper的一部分流程了、

Mybatis源码学习1-配置解析1-SqlSessionFactoryBuilder

Mybatis源码学习3-mapper解析-动态代理的生成

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值