mybatis源码分析如何获取数据源和SQL语句

Mybatis官方文档

https://mybatis.org/mybatis-3/zh/logging.html

mybatis源码分析如何获取数据源和SQL语句

Mybatis源码分析

一、mybatis如何获取数据源

org.apache.ibatis.session.SqlSessionFactoryBuilder.build(java.io.InputStream)
》org.apache.ibatis.builder.xml.XMLConfigBuilder.parse
   》org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration
    》org.apache.ibatis.builder.xml.XMLConfigBuilder.environmentsElement
      》org.apache.ibatis.builder.xml.XMLConfigBuilder.dataSourceElement
       》org.apache.ibatis.session.Configuration.setEnvironment#######
123456

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(image/20200702142235696.png)(C:\Users\shine\AppData\Roaming\Typora\typora-user-images\image-20200702141922022.png)]

1、org.apache.ibatis.session.SqlSessionFactoryBuilder.build(java.io.InputStream)

获取mybatis-config.xml文件

2、org.apache.ibatis.builder.xml.XMLConfigBuilder.parse

加载mybatis-config.xml配置文件

3、org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration

对mybatis-config.xml文件进行解析

private void parseConfiguration(XNode root) {
        try {
            //获取Properties标签中的内容
            this.propertiesElement(root.evalNode("properties"));
            //获取缓存
            Properties settings = this.settingsAsProperties(root.evalNode("settings"));
            this.loadCustomVfs(settings);
           	//加载别名 
            this.typeAliasesElement(root.evalNode("typeAliases"));
            //加载拦截器
            this.pluginElement(root.evalNode("plugins"));
            //用于加载对象工厂(用于创建对象的实例)
            this.objectFactoryElement(root.evalNode("objectFactory"));
            //用于加载对象包装工程
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            //用于反射实体类中的属性字段
            this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
            this.settingsElement(settings);
            //加载数据源
            this.environmentsElement(root.evalNode("environments"));
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            //用于实现JDBC和JAVA类型之间的转换
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            //加载Mappers标签中的内容,也就是写SQL语句的位置
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }
1234567891011121314151617181920212223242526272829

4、org.apache.ibatis.builder.xml.XMLConfigBuilder.environmentsElement

加载数据源

private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
        if (this.environment == null) {
            this.environment = context.getStringAttribute("default");
        }

        Iterator var2 = context.getChildren().iterator();

        while(var2.hasNext()) {
            XNode child = (XNode)var2.next();
            String id = child.getStringAttribute("id");
            if (this.isSpecifiedEnvironment(id)) {
                TransactionFactory txFactory = this.transactionManagerElement(child.evalNode("transactionManager"));
                //下面这个方法会对数据源进行解析
                DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));
                //获取到数据源
                DataSource dataSource = dsFactory.getDataSource();
                Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
                this.configuration.setEnvironment(environmentBuilder.build());
            }
        }
    }
}
1234567891011121314151617181920212223

5、org.apache.ibatis.builder.xml.XMLConfigBuilder.dataSourceElement

解析数据源

private DataSourceFactory dataSourceElement(XNode context) throws Exception {
    if (context != null) {
        //获取dataSource标签的一个类型
        String type = context.getStringAttribute("type");
        //取出数据源,Driver、URL、Username、Password
        Properties props = context.getChildrenAsProperties();
        //通过反射的形式来获取对应的工厂实例
        DataSourceFactory factory = (DataSourceFactory)this.resolveClass(type).newInstance();
        factory.setProperties(props);
        return factory;
    } else {
        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
    }
}
1234567891011121314

6、org.apache.ibatis.session.Configuration.setEnvironment

加载数据源会放在这个类中,包括了连接的最大数量、最小数量、过期时间等

二、mybatis是如何获取SQL语句的

org.apache.ibatis.session.SqlSessionFactoryBuilder.build(java.io.InputStream)
》org.apache.ibatis.builder.xml.XMLConfigBuilder.parse
   》org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration
     》org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement
       》org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement
         》org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode
           >org.apache.ibatis.session.Configuration.addMappedStatement######
1234567

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(image/20200702142254324.png)(C:\Users\shine\AppData\Roaming\Typora\typora-user-images\image-20200702142003187.png)]

1、org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement

解析Mapper的加载方式

private void mapperElement(XNode parent) throws Exception {
    	/**
    	 *  parent的内容是Mappers标签中的内容(包括了Mappers标签)
         *  <mappers>
         *  <mapper resource="mapper/ExJobMapper.xml"/>
         *  </mappers>
    	*/
        if (parent != null) {
            Iterator var2 = parent.getChildren().iterator();

            while(true) {
                while(var2.hasNext()) {
                    XNode child = (XNode)var2.next();
                    String resource;
                    //判断Mappers的加载方式是否为Package,优先判断
                    if ("package".equals(child.getName())) {
                        resource = child.getStringAttribute("name");
                        this.configuration.addMappers(resource);
                    } else {
                        resource = child.getStringAttribute("resource");
                        String url = child.getStringAttribute("url");
                        String mapperClass = child.getStringAttribute("class");
                        XMLMapperBuilder mapperParser;
                        InputStream inputStream;
                        //判断加载方式是否为Resource
                        if (resource != null && url == null && mapperClass == null) {
                            ErrorContext.instance().resource(resource);
                            inputStream = Resources.getResourceAsStream(resource);
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        //判断加载方式是否为URL
                        } 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 {
                            //判断加载方式是否为Class加载
                            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;
            }
        }
    }
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152

2、org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement

解析Mappers中的各种相关配置

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"));
                //解析SQL语句
                this.sqlElement(context.evalNodes("/mapper/sql"));
                //判断SQL语句是DQL还是DML
                this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
            } else {
                throw new BuilderException("Mapper's namespace cannot be empty");
            }
        } catch (Exception var3) {
            throw new BuilderException("Error parsing Mapper XML. The XML location is '" + this.resource + "'. Cause: " + var3, var3);
        }
    }
12345678910111213141516171819202122232425

3、org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode

解析Mappers中SQL标签的各种配置

public void parseStatementNode() {
    	//获取SQL标签中的Id
        String id = this.context.getStringAttribute("id");
    	//数据库的ID
        String databaseId = this.context.getStringAttribute("databaseId");
        if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
            Integer fetchSize = this.context.getIntAttribute("fetchSize");
            Integer timeout = this.context.getIntAttribute("timeout");
            String parameterMap = this.context.getStringAttribute("parameterMap");
            String parameterType = this.context.getStringAttribute("parameterType");
            Class<?> parameterTypeClass = this.resolveClass(parameterType);
            String resultMap = this.context.getStringAttribute("resultMap");
            String resultType = this.context.getStringAttribute("resultType");
            String lang = this.context.getStringAttribute("lang");
            LanguageDriver langDriver = this.getLanguageDriver(lang);
            Class<?> resultTypeClass = this.resolveClass(resultType);
            String resultSetType = this.context.getStringAttribute("resultSetType");
            StatementType statementType = StatementType.valueOf(this.context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
            ResultSetType resultSetTypeEnum = this.resolveResultSetType(resultSetType);
            //获取标签头(例如SELECT、DELETE、UPDATE、INSERT)
            String nodeName = this.context.getNode().getNodeName();
            SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
            boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
            boolean flushCache = this.context.getBooleanAttribute("flushCache", !isSelect);
            boolean useCache = this.context.getBooleanAttribute("useCache", isSelect);
            boolean resultOrdered = this.context.getBooleanAttribute("resultOrdered", false);
            XMLIncludeTransformer includeParser = new XMLIncludeTransformer(this.configuration, this.builderAssistant);
            includeParser.applyIncludes(this.context.getNode());
            this.processSelectKeyNodes(id, parameterTypeClass, langDriver);
            //获取到完整的一条SQL语句
            SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);
            String resultSets = this.context.getStringAttribute("resultSets");
            String keyProperty = this.context.getStringAttribute("keyProperty");
            String keyColumn = this.context.getStringAttribute("keyColumn");
            String keyStatementId = id + "!selectKey";
            keyStatementId = this.builderAssistant.applyCurrentNamespace(keyStatementId, true);
            Object keyGenerator;
            if (this.configuration.hasKeyGenerator(keyStatementId)) {
                keyGenerator = this.configuration.getKeyGenerator(keyStatementId);
            } else {
                keyGenerator = this.context.getBooleanAttribute("useGeneratedKeys", this.configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
            }

            this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
        }
    }
12345678910111213141516171819202122232425262728293031323334353637383940414243444546

4、org.apache.ibatis.session.Configuration.setEnvironment

将加载好的结果存放在该类中并且返回

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值