10.MyBatis源码分析笔记

通过Debug分析源码01

Posted by Chen Xingxu on September 15, 2020

10.MyBatis源码分析笔记–通过Debug分析源码01

宏观认识 MyBatis

MyBatis 本质上是一个 ORM 框架(Object Relational Mapping),用于实现面向对象编程语言里不同类型系统的数据之间的转换。

整体运行流程

MyBatis 处理流程图

微观分析 MyBatis 源码

Mybatis 如何获取数据库源

为 org.apache.ibatis.demo.MybatisMain 中的以下代码设置断点:

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

进入 Debug 模式。

Debug 流程

  1. 进入断点

  2. Step Into(F7)

  3. Step Into(F7)

  4. Step Into(F7)

  5. Step Into(F7)

  6. Step Over(F8)

  7. Step Into(F7): parse

  8. Step Over(F8)

  9. Step Over(F8)

  10. Step Into(F7): evalNode

  11. XNode 对象属性

    1.   private final Node node;
        private final String name;
        private final String body;
        private final Properties attributes;
        private final Properties variables;
        private final XPathParser xpathParser;
      
  12. Step Out(Shift + F8)

  13. Step Into(F7): parseConfiguration

  14. 查看 parseConfiguration(XNode root) 中传入的 root 的值

    1. Evaluate Expression

    2. Evaluate

    3. Copy Value

    4. 实际上就是 mybatis-config.xml 配置文件中 configuration 标签下的内容

      1. <configuration>
            <properties resource="config.properties">
            </properties>
            <typeAliases>
                <typeAlias alias="user" type="org.apache.ibatis.demo.pojo.User"/>        
            </typeAliases>
            <plugins>
                <plugin interceptor="org.apache.ibatis.demo.plugin.SqlPrintInterceptor"/>        
            </plugins>
            <environments default="development">
                <environment id="development">
                    <transactionManager type="JDBC"/>            
                    <dataSource type="POOLED">
                        <property name="driver" value="${driver}"/>                
                        <property name="url" value="${url}"/>                
                        <property name="username" value="${username}"/>                
                        <property name="password" value="${password}"/>                
                    </dataSource>
                </environment>
            </environments>
            <mappers>
                <mapper resource="mapper/UserMapper.xml"/>        
            </mappers>
        </configuration>
                  
        
  15. 解析 configuration 标签下的内容

    1. //org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration
      //---
      parseConfiguration(parser.evalNode("/configuration"));
      //---
             
      //org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration
      //解析 configuration 标签下的内容
      //---
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
      //---
      
    2. configuration 标签下的标签(参考:https://mybatis.org/mybatis-3/configuration.html

      1. properties
      2. settings
      3. typeAliases
      4. typeHandlers
      5. objectFactory
      6. plugins
      7. environments
      8. databaseIdProvider
      9. mappers
  16. Step Into(F7): propertiesElement

  17. 查看 propertiesElement(XNode context) 中传入的 context 的值

    1. 实际上就是 mybatis-config.xml 配置文件中 properties 标签下的内容

      1. <properties resource="config.properties">
            </properties>
        
      2. 通过 propertiesElement 方法将 config.properties 中的内容以键值对的形式存入到 parser(org.apache.ibatis.parsing.XPathParser) 和 configuration(org.apache.ibatis.session.Configuration) 中

        1. if (context != null) {
                //java.util.Properties
                //public class Properties extends Hashtable<Object,Object>
                Properties defaults = context.getChildrenAsProperties();
                String resource = context.getStringAttribute("resource");
                String url = context.getStringAttribute("url");
                if (resource != null && url != null) {
                  throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
                }
                if (resource != null) {
                  //java.util.Properties#putAll
                  //public synchronized void putAll(Map<?, ?> t)
                  defaults.putAll(Resources.getResourceAsProperties(resource));
                } else if (url != null) {
                  defaults.putAll(Resources.getUrlAsProperties(url));
                }
                //org.apache.ibatis.session.Configuration#getVariables
                //public Properties getVariables()
                Properties vars = configuration.getVariables();
                if (vars != null) {
                  defaults.putAll(vars);
                }
                //org.apache.ibatis.parsing.XPathParser
                //private final XPathParser parser
                parser.setVariables(defaults);
                //org.apache.ibatis.session.Configuration
                //protected final Configuration configuration
                configuration.setVariables(defaults);
          }
          
  18. Step Into(F7): environmentsElement

  19. 查看 environmentsElement(XNode context) 中传入的 context 的值

    1. 实际上就是 mybatis-config.xml 配置文件中 environments 标签下的内容

      1. <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>        
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>            
                    <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_learn?characterEncoding=utf8&serverTimezone=UTC&useSSL=false"/>            
                    <property name="username" value="root"/>            
                    <property name="password" value="root123456"/>            
                </dataSource>
            </environment>
        </environments>
                  
        
  20. Resume Programe(F9)

  21. Step Into: dataSourceElement

  22. 查看 dataSourceElement(XNode context) 中传入的 context 的值

    1. <dataSource type="POOLED">
          <property name="driver" value="com.mysql.cj.jdbc.Driver"/>    
          <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_learn?characterEncoding=utf8&serverTimezone=UTC&useSSL=false"/>    
          <property name="username" value="root"/>    
          <property name="password" value="root123456"/>    
      </dataSource>
      
  23. 通过 dataSourceElement 方法解析 dataSource 标签下的内容

    1. if (context != null) {
            String type = context.getStringAttribute("type");
            Properties props = context.getChildrenAsProperties();
            DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
            factory.setProperties(props);
            return factory;
      }
      throw new BuilderException("Environment declaration requires a DataSourceFactory.");
      
    2. props 的内容

  24. Step Into: resolveClass

  25. Step Over

  26. Step Into

  27. Step Into

  28. Step Over

  29. Step Over

  30. Step Over

  31. Step Over

  32. Evaluate Expression: typeAliases.get(key)

    1. class org.apache.ibatis.datasource.pooled.PooledDataSourceFactory
      
  33. Step Over

  34. Step Over

  35. Step Over

  36. Step Over

    1. 通过 getDeclaredConstructor 方法获取 PooledDataSourceFactory 类的制定参数类型的所有构造器,包括 public 的和非 public 的,当然也包括 private 的。
    2. 通过 newInstance 方法将 PooledDataSourceFactory 类变成一个对象。
  37. Step Over

  38. Step Over

  39. Step Over

  40. Step Into

    1. 返回当前的数据库源
  41. Step Over

  42. Step Over

  43. Evaluate Expression: dataSource

  44. 通过 for (XNode child : context.getChildren()) 循环,说明 dataSource 可以配置多个。

  45. Step Over

  46. Step Into: setEnvironment

  47. org.apache.ibatis.mapping.Environment 的属性

    1. private final String id;
      private final TransactionFactory transactionFactory;
      private final DataSource dataSource;
      
    2. 与 mybatis-config.xml 的属性一一对应

      1. <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
        
  48. Step Over

  49. Step Over

  50. Step Over

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.propertiesElement
│  │  │  │  ├─org.apache.ibatis.session.Configuration.setVariables
│  │  │  ├─org.apache.ibatis.builder.xml.XMLConfigBuilder.environmentsElement
│  │  │  │  ├─org.apache.ibatis.session.Configuration.setEnvironment
│  │  │  │  │  ├─org.apache.ibatis.builder.xml.XMLConfigBuilder.dataSourceElement
│  │  │  │  │  │  ├─org.apache.ibatis.builder.BaseBuilder.resolveClass
│  │  │  │  │  │  │  ├─org.apache.ibatis.builder.BaseBuilder.resolveAlias
│  │  │  │  │  │  │  │  ├─org.apache.ibatis.type.TypeAliasRegistry.resolveAlias
│  │  │  │  │  │  ├─java.lang.Class.getDeclaredConstructor
│  │  │  │  │  │  ├─java.lang.reflect.Constructor.newInstance
│  │  │  │  │  │  ├─org.apache.ibatis.datasource.DataSourceFactory.setProperties

画图分析 MyBatis 源码