Mybatis源码解析(二):全局配置文件的解析

Mybatis源码系列文章

手写源码(了解源码整体流程及重要组件)

Mybatis源码解析(一):环境搭建

Mybatis源码解析(二):全局配置文件的解析

Mybatis源码解析(三):映射配置文件的解析

Mybatis源码解析(四):sql语句及#{}、${}的解析

Mybatis源码解析(五):SqlSession会话的创建

Mybatis源码解析(六):缓存执行器操作流程

Mybatis源码解析(七):查询数据库主流程

Mybatis源码解析(八):Mapper代理原理

Mybatis源码解析(九):插件机制

Mybatis源码解析(十):一级缓存和二级缓存



一、加载配置文件

环境搭建章节,通过传统方式测试如下:

@Test
public void test1() throws IOException {

  InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

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

  SqlSession sqlSession = sqlSessionFactory.openSession();

  User user = sqlSession.selectOne("user.findUserById", 100);

  System.out.println(user);

  sqlSession.close();
}

第一步操作:Resources.getResourceAsStream(“sqlMapConfig.xml”)

  • 通过类加载器对配置文件进行加载,加载成了字节输入流,存到内存中
  • 注意:配置文件并没有被解析,只是转换成输入流对象

二、会话工厂Build类的构建

1、构建者设计模式

  • 创建对象方式:Dept tom = Dept.newBuilder().deptno(1).dname(“tom”).build();
  • 优点:将一个复杂对象每个部分的创建分离开,链式调用,思路清晰
public class Dept {
    private Integer deptno;
    private String dname;

    //步骤5:实体类提供全参构造方法
    private Dept(Integer deptno, String dname) {
        this.deptno = deptno;
        this.dname = dname;
    }

    public static DeptBuilder newBuilder() { //步骤 2:提供返回Builder的静态方法
        return new DeptBuilder();
    }

    public static class DeptBuilder {  //步骤 1:定义Builder类
        //步骤3:提供和实体类一样的属性
        private Integer deptno;
        private String dname;

        //步骤4:提供设置属性的方法
        public DeptBuilder deptno(Integer deptno) {
            this.deptno = deptno;
            return this;
        }

        public DeptBuilder dname(String dname) {
            this.dname = dname;
            return this;
        }

        public Dept build(){ //步骤6:提供返回实体类的方法
            return new Dept(deptno,dname);
        }
    }
}

2、build构建重载方法

第二步操作:new SqlSessionFactoryBuilder().build(resourceAsStream)

  • new SqlSessionFactoryBuilder():这里只是调用会话工厂构建类的无参方法,无其他动作
  • build方法涉及多个重载方法
    • inputStream:核心配置文件的字节输入流
    • environment:核心配置文件中<environment>标签的id值,build方法调用时候可以添加环境id,不传的话,后续会从<environments>标签的默认值中获取环境id值
    • properties:旧对象,已不再使用

在这里插入图片描述
在这里插入图片描述

三、build构建方法:创建【核心配置文件解析类】

build方法实现类

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
   try {
     // XMLConfigBuilder:用来解析XML配置文件
     // 使用构建者模式:好处:降低耦合、分离复杂对象的创建
     // 1.创建XPathParser解析器对象,根据inputStream解析成了document对象 2.创建全局配置对象Configuration对象
     XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);

     // parser.parse():使用XPATH解析XML配置文件,将配置文件封装到Configuration对象
     // 返回DefaultSqlSessionFactory对象,该对象拥有Configuration对象(封装配置文件信息)
     // parse():配置文件就解析完成了
     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.
     }
   }
 }

1、BaseBuilder类图

在这里插入图片描述

  • 这些子类基本上都是以Builder结尾,这里使用的是Builder建造者设计模式
  • 不同的Builder类对应不同组件的内容解析
  • XMLConfigBuilder:解析核心配置文件xml类;XMLMapperBuilder:解析实体映射配置文件xml类

XMLConfigBuilder构造方法

  • XPathParser:将xml字节输入流转换为Document对象,存入XPathParser,而XPathParser对象引用放到XMLConfigBuilder对象parser属性中
  • 环境id也赋值到XMLConfigBuilder属性中
  • parsed属性:核心配置文件是否被解析,解析后会被赋值为true,表示只能解析一次
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
  // XPathParser基于 Java XPath 解析器,用于解析 MyBatis中的配置文件
  this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
  //  创建Configuration对象,并通过TypeAliasRegistry注册一些Mybatis内部相关类的别名
  super(new Configuration());
  ErrorContext.instance().resource("SQL Mapper Configuration");
  this.configuration.setVariables(props);
  this.parsed = false;
  this.environment = environment;
  this.parser = parser;
}

2、创建Configuration对象

Configuration对象

  • 核心配置文件xml可以配置的标签如下

  • 核心配置文件将会被解析为Configuration配置类,而里面的标签则会被解析为对应的属性
    在这里插入图片描述

  • environment中包含statementId:“namespace.id”、事务工厂和数据源信息

public class Configuration {
  protected Environment environment;
  // 允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。默认为false
  protected boolean safeRowBoundsEnabled;
  // 允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为false
  protected boolean safeResultHandlerEnabled = true;
  // 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN
  // 到经典 Java 属性名 aColumn 的类似映射。默认false
  protected boolean mapUnderscoreToCamelCase;
  // 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。默认值false (true in ≤3.4.1)
  protected boolean aggressiveLazyLoading;
  // 是否允许单一语句返回多结果集(需要兼容驱动)。
  protected boolean multipleResultSetsEnabled = true;
  // 允许 JDBC 支持自动生成主键,需要驱动兼容。这就是insert时获取mysql自增主键/oracle sequence的开关。
  // 注:一般来说,这是希望的结果,应该默认值为true比较合适。
  protected boolean useGeneratedKeys;
  // 使用列标签代替列名,一般来说,这是希望的结果
  protected boolean useColumnLabel = true;
  // 是否启用缓存
  protected boolean cacheEnabled = true;
  // 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,
  // 这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。
  protected boolean callSettersOnNulls;
  // 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,
  // 并且加上-parameters选项。(从3.4.1开始)
  protected boolean useActualParamName = true;
  //当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。
  // 请注意,它也适用于嵌套的结果集 (i.e. collectioin and association)。(从3.4.2开始)
  // 注:这里应该拆分为两个参数比较合适, 一个用于结果集,一个用于单记录。
  // 通常来说,我们会希望结果集不是null,单记录仍然是null
  protected boolean returnInstanceForEmptyRow;

  protected boolean shrinkWhitespacesInSql;

  // 指定 MyBatis 增加到日志名称的前缀。
  protected String logPrefix;
  // 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。一般建议指定为slf4j或log4j
  protected Class<? extends Log> logImpl;
  // 指定VFS的实现, VFS是mybatis提供的用于访问AS内资源的一个简便接口
  protected Class<? extends VFS> vfsImpl;
  protected Class<?> defaultSqlProviderType;
  // MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。
  // 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。
  // 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。
  protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
  // 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,
  // 多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
  protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
  // 指定对象的哪个方法触发一次延迟加载。
  protected Set<String> lazyLoadTriggerMethods 
  							= new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
  // 设置超时时间,它决定驱动等待数据库响应的秒数。默认不超时
  protected Integer defaultStatementTimeout;
  // 为驱动的结果集设置默认获取数量。
  protected Integer defaultFetchSize;
  // SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements);
  // BATCH 执行器将重用语句并执行批量更新。
  protected ResultSetType defaultResultSetType;

  // 默认执行器类型
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  // 指定 MyBatis 应如何自动映射列到字段或属性。
  // NONE 表示取消自动映射;
  // PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。
  // FULL 会自动映射任意复杂的结果集(无论是否嵌套)。
  protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
  // 指定发现自动映射目标未知列(或者未知属性类型)的行为。这个值应该设置为WARNING比较合适
  protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior 
  													= AutoMappingUnknownColumnBehavior.NONE;
  // settings下的properties属性
  protected Properties variables = new Properties();
  // 默认的反射器工厂,用于操作属性、构造器方便
  protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
  // 对象工厂, 所有的类resultMap类都需要依赖于对象工厂来实例化
  protected ObjectFactory objectFactory = new DefaultObjectFactory();
  // 对象包装器工厂,主要用来在创建非原生对象,比如增加了某些监控或者特殊属性的代理类
  protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();

  // 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态
  protected boolean lazyLoadingEnabled = false;
  // 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。MyBatis 3.3+使用JAVASSIST
  protected ProxyFactory proxyFactory = new JavassistProxyFactory(); 

  // MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。
  protected String databaseId;
  /**
   * Configuration factory class.
   * Used to create Configuration for loading deserialized unread properties.
   *
   */
  protected Class<?> configurationFactory;

  protected final MapperRegistry mapperRegistry = new MapperRegistry(this);

  // mybatis插件列表
  protected final InterceptorChain interceptorChain = new InterceptorChain();
  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);

  // 类型注册器, 用于在执行sql语句的出入参映射以及mybatis-config文件里的各种配置
  // 比如<transactionManager type="JDBC"/><dataSource type="POOLED">时使用简写
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
  protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

  protected final Map<String, MappedStatement> mappedStatements = 
  new StrictMap<MappedStatement>("Mapped Statements collection")
      .conflictMessageProducer((savedValue, targetValue) ->
          ". please check " + savedValue.getResource() + " and " + targetValue.getResource());
  protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
  protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
  protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
  protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");

  protected final Set<String> loadedResources = new HashSet<>();
  protected final Map<String, XNode> sqlFragments 
  							= new StrictMap<>("XML fragments parsed from previous mappers");

  protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
  protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
  protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<>();
  protected final Collection<MethodResolver> incompleteMethods = new LinkedList<>();

  /*
   * A map holds cache-ref relationship. The key is the namespace that
   * references a cache bound to another namespace and the value is the
   * namespace which the actual cache is bound to.
   */
  protected final Map<String, String> cacheRefMap = new HashMap<>();

  public Configuration(Environment environment) {
    this();
    this.environment = environment;
  }
  
  ...
  
}

Configuration构造函数

  • TypeAliasRegistry(类型别名注册器):注册以后就可以在xml中直接使用别名

在这里插入图片描述

public Configuration() {
  /**
   *  注册事务工厂的别名
   */
  // 利用java.sql.Connection对象完成对事务的提交
  typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
  // mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理
  typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

  /**
   *  注册数据源的别名
   */
  // mybatis会从在应用服务器向配置好的JNDI数据源DataSource获取数据库连接。在生产环境中优先考虑这种方式
  typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
  // mybatis会创建一个数据库连接池,连接池的一个连接将会被用作数据库操作。一旦数据库操作完成,
  // mybatis会将此连接返回给连接池。在开发或测试环境中经常用到此方式
  typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
  // mybatis会为每一个数据库操作创建一个新的连接,并关闭它。该方式适用于只有小规模数量并发用户的简单应用程序上
  typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

  // 注册缓存策略的别名
  typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
  typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
  typeAliasRegistry.registerAlias("LRU", LruCache.class);
  typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
  typeAliasRegistry.registerAlias("WEAK", WeakCache.class);

  typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

  typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
  typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

  // 注册日志类的别名
  typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
  typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
  typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
  typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
  typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
  typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
  typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

  // 注册动态代理工厂的别名
  typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
  typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

  languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
  languageRegistry.register(RawLanguageDriver.class);
}

JDBC事务工厂类

public class JdbcTransactionFactory implements TransactionFactory {

  @Override
  public Transaction newTransaction(Connection conn) {
    return new JdbcTransaction(conn);
  }

  @Override
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }
}

构造函数:连接、隔离级别、是否自动提交

public class JdbcTransaction implements Transaction {

  private static final Log log = LogFactory.getLog(JdbcTransaction.class);

  protected Connection connection;
  protected DataSource dataSource;
  protected TransactionIsolationLevel level;
  protected boolean autoCommit;

  public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
    dataSource = ds;
    level = desiredLevel;
    autoCommit = desiredAutoCommit;
  }

...
}
  • 其他工厂类类似,xml中注册工厂类,使用时候通过工厂类的Class对象反射调用new方法创建需要的对象
  • super(new Configuration()); 最后创建完成的Configuration对象引用会放到抽象类BaseBuilder中
  • 再回头看BaseBuilder类图,也就是说configuration对象将要被解析到XMLConfigBuilder对象中

四、build构建方法:调用【核心配置文件解析类】的解析方法

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      // XMLConfigBuilder:用来解析XML配置文件
      // 使用构建者模式:好处:降低耦合、分离复杂对象的创建
      // 1.创建XPathParser解析器对象,根据inputStream解析成了document对象 2.创建全局配置对象Configuration对象
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);

      // parser.parse():使用XPATH解析XML配置文件,将配置文件封装到Configuration对象
      // 返回DefaultSqlSessionFactory对象,该对象拥有Configuration对象(封装配置文件信息)
      // parse():配置文件就解析完成了
      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.
      }
    }
  }

进入XMLConfigBuilder类的parse()解析方法中

  • parsed属性即XMLConfigBuilder构造函数中的值,默认false,代表只能解析一次,这里也应验了
  • “parser.evalNode(“/configuration”)”返回XNode对象,<Configration>标签及其子标签都被封装到此对象中
public Configuration parse() {
  if (parsed) {
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
  }
  parsed = true;
  
  // parser.evalNode("/configuration"):通过XPATH解析器,解析configuration根节点
  // 从configuration根节点开始解析,最终将解析出的内容封装到Configuration对象中
  parseConfiguration(parser.evalNode("/configuration"));

  return configuration;
}

进parseConfiguration方法解析XNode对象

private void parseConfiguration(XNode root) {
  try {
    // 解析</properties>标签
    propertiesElement(root.evalNode("properties"));
    // 解析</settings>标签
    Properties settings = settingsAsProperties(root.evalNode("settings"));
    loadCustomVfs(settings);
    loadCustomLogImpl(settings);
    // 解析</typeAliases>标签
    typeAliasesElement(root.evalNode("typeAliases"));
    // 解析</plugins>标签
    pluginElement(root.evalNode("plugins"));
    // 解析</objectFactory>标签
    objectFactoryElement(root.evalNode("objectFactory"));
    // 解析</objectWrapperFactory>标签
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    // 解析</reflectorFactory>标签
    reflectorFactoryElement(root.evalNode("reflectorFactory"));
    settingsElement(settings);
    // read it after objectFactory and objectWrapperFactory issue #631
    // 解析</environments>标签
    environmentsElement(root.evalNode("environments"));
    // 解析</databaseIdProvider>标签
    databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    // 解析</typeHandlers>标签
    typeHandlerElement(root.evalNode("typeHandlers"));
    // 解析</mappers>标签 加载映射文件流程主入口
    mapperElement(root.evalNode("mappers"));
  } catch (Exception e) {
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
  }
}

1、解析<environments>标签内容

<configuration>标签下的子标签很多,目前咱们配置文件只有<environments>标签和<mappers>标签(映射配置文件-下一章单独来讲)

进入environmentsElement(root.evalNode(“environments”));

  • root.evalNode(“environments”)返回XNode对象,<environments>标签及其子标签都被封装到context对象中
  • new SqlSessionFactoryBuilder().build(resourceAsStream)方法没传环境id,则会去获取默认环境id
private void environmentsElement(XNode context) throws Exception {
  // 如果定义了environments
  if (context != null) {
    // 方法参数如何没有传递 environment,则解析sqlMapConfig.xml中的
    if (environment == null) {
      // <environments default="development" >
      environment = context.getStringAttribute("default");
    }

    //遍历解析environment节点
    for (XNode child : context.getChildren()) {
      //获得id属性值
      String id = child.getStringAttribute("id");
      //判断id和environment值是否相等
      if (isSpecifiedEnvironment(id)) {
        /*
            <transactionManager type="JDBC" />
            创建事务工厂对象
         */
        TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
        /*
            <dataSource type="POOLED">
            创建数据源对象
         */
        DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
        DataSource dataSource = dsFactory.getDataSource();
        Environment.Builder environmentBuilder = new Environment.Builder(id)
            .transactionFactory(txFactory)
            .dataSource(dataSource);

        // 将Environment存到configuraion中
        configuration.setEnvironment(environmentBuilder.build());
        break;
      }
    }
  }
}

1)创建事务工厂对象

在这里插入图片描述

  • child.evalNode(“transactionManager”):获取<transactionManager>标签及其子标签内容,封装到XNode对象
  • 获取type属性值即JDBC,而JDBC别名对应JdbcTransactionFactory事务工厂类
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
  if (context != null) {
    String type = context.getStringAttribute("type");
    Properties props = context.getChildrenAsProperties();
    //通过Class对象构造函数创建对象
    TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance();
    factory.setProperties(props);
    return factory;
  }
  throw new BuilderException("Environment declaration requires a TransactionFactory.");
}

2)创建数据源工厂对象

  • 与创建事务工厂代码基本一样,获取PooledDataSourceFactory的Class对象,再反射获取工厂对象
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
  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.");
}

构建Environment对象,赋值configuration

  • 通过构建者模式创建Environment对象
  • configuration.setEnvironment(environmentBuilder.build());将Environment存到configuraion中
  • 至此<environments>标签内容解析完毕
public final class Environment {
  private final String id;
  private final TransactionFactory transactionFactory;
  private final DataSource dataSource;
  
  ...
}

五、默认会话工厂的构建

  • 核心配置文件解析完成返回Configuration对象,这里开始构建会话工厂对象
public SqlSessionFactory build(Configuration config) {
  return new DefaultSqlSessionFactory(config);
}
  • 默认会话工厂实现了SqlSessionFactory
  • SqlSessionFactory接口中有很多openSession重载方法,通过不同方式创建SqlSession
  • 具体实现,后面篇章再说
  • 回到第一章节,至此SqlSessionFactoryBuilder类build会话工厂任务完成
public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }

  @Override
  public SqlSession openSession() {
    // 调用openSessionFromDataSource 参数1:执行器类型  参数2:事务隔离级别  参数三:指定事务是否自动提交
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
  
  ...
}

总结

  • Mybatis入口从加载配置文件→输入流→Document对象→XNode对象
  • 从创建XMLConfigBuilder→Configuration→解析核心xml填充Configuration对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬天vs不冷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值